1
# This module should be kept compatible with Python 2.1.
3
__revision__ = "$Id: install_lib.py 61000 2008-02-23 17:40:11Z christian.heimes $"
6
from types import IntType
7
from distutils.core import Command
8
from distutils.errors import DistutilsOptionError
11
# Extension for Python source files.
12
if hasattr(os, 'extsep'):
13
PYTHON_SOURCE_EXTENSION = os.extsep + "py"
15
PYTHON_SOURCE_EXTENSION = ".py"
17
class install_lib (Command):
19
description = "install all Python modules (extensions and pure Python)"
21
# The byte-compilation options are a tad confusing. Here are the
23
# 1) no compilation at all (--no-compile --no-optimize)
24
# 2) compile .pyc only (--compile --no-optimize; default)
25
# 3) compile .pyc and "level 1" .pyo (--compile --optimize)
26
# 4) compile "level 1" .pyo only (--no-compile --optimize)
27
# 5) compile .pyc and "level 2" .pyo (--compile --optimize-more)
28
# 6) compile "level 2" .pyo only (--no-compile --optimize-more)
30
# The UI for this is two option, 'compile' and 'optimize'.
31
# 'compile' is strictly boolean, and only decides whether to
32
# generate .pyc files. 'optimize' is three-way (0, 1, or 2), and
33
# decides both whether to generate .pyo files and what level of
34
# optimization to use.
37
('install-dir=', 'd', "directory to install to"),
38
('build-dir=','b', "build directory (where to install from)"),
39
('force', 'f', "force installation (overwrite existing files)"),
40
('compile', 'c', "compile .py to .pyc [default]"),
41
('no-compile', None, "don't compile .py files"),
43
"also compile with optimization: -O1 for \"python -O\", "
44
"-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
45
('skip-build', None, "skip the build steps"),
48
boolean_options = ['force', 'compile', 'skip-build']
49
negative_opt = {'no-compile' : 'compile'}
52
def initialize_options (self):
53
# let the 'install' command dictate our installation directory
54
self.install_dir = None
59
self.skip_build = None
61
def finalize_options (self):
63
# Get all the information we need to install pure Python modules
64
# from the umbrella 'install' command -- build (source) directory,
65
# install (target) directory, and whether to compile .py files.
66
self.set_undefined_options('install',
67
('build_lib', 'build_dir'),
68
('install_lib', 'install_dir'),
70
('compile', 'compile'),
71
('optimize', 'optimize'),
72
('skip_build', 'skip_build'),
75
if self.compile is None:
77
if self.optimize is None:
80
if type(self.optimize) is not IntType:
82
self.optimize = int(self.optimize)
83
assert 0 <= self.optimize <= 2
84
except (ValueError, AssertionError):
85
raise DistutilsOptionError, "optimize must be 0, 1, or 2"
89
# Make sure we have built everything we need first
92
# Install everything: simply dump the entire contents of the build
93
# directory to the installation directory (that's the beauty of
94
# having a build directory!)
95
outfiles = self.install()
97
# (Optionally) compile .py to .pyc
98
if outfiles is not None and self.distribution.has_pure_modules():
99
self.byte_compile(outfiles)
104
# -- Top-level worker functions ------------------------------------
105
# (called from 'run()')
108
if not self.skip_build:
109
if self.distribution.has_pure_modules():
110
self.run_command('build_py')
111
if self.distribution.has_ext_modules():
112
self.run_command('build_ext')
115
if os.path.isdir(self.build_dir):
116
outfiles = self.copy_tree(self.build_dir, self.install_dir)
118
self.warn("'%s' does not exist -- no Python modules to install" %
123
def byte_compile (self, files):
124
from distutils.util import byte_compile
126
# Get the "--root" directory supplied to the "install" command,
127
# and use it as a prefix to strip off the purported filename
128
# encoded in bytecode files. This is far from complete, but it
129
# should at least generate usable bytecode in RPM distributions.
130
install_root = self.get_finalized_command('install').root
133
byte_compile(files, optimize=0,
134
force=self.force, prefix=install_root,
135
dry_run=self.dry_run)
136
if self.optimize > 0:
137
byte_compile(files, optimize=self.optimize,
138
force=self.force, prefix=install_root,
139
verbose=self.verbose, dry_run=self.dry_run)
142
# -- Utility methods -----------------------------------------------
144
def _mutate_outputs (self, has_any, build_cmd, cmd_option, output_dir):
149
build_cmd = self.get_finalized_command(build_cmd)
150
build_files = build_cmd.get_outputs()
151
build_dir = getattr(build_cmd, cmd_option)
153
prefix_len = len(build_dir) + len(os.sep)
155
for file in build_files:
156
outputs.append(os.path.join(output_dir, file[prefix_len:]))
162
def _bytecode_filenames (self, py_filenames):
164
for py_file in py_filenames:
165
# Since build_py handles package data installation, the
166
# list of outputs can contain more than just .py files.
167
# Make sure we only report bytecode for the .py files.
168
ext = os.path.splitext(os.path.normcase(py_file))[1]
169
if ext != PYTHON_SOURCE_EXTENSION:
172
bytecode_files.append(py_file + "c")
173
if self.optimize > 0:
174
bytecode_files.append(py_file + "o")
176
return bytecode_files
179
# -- External interface --------------------------------------------
180
# (called by outsiders)
182
def get_outputs (self):
183
"""Return the list of files that would be installed if this command
184
were actually run. Not affected by the "dry-run" flag or whether
185
modules have actually been built yet.
188
self._mutate_outputs(self.distribution.has_pure_modules(),
189
'build_py', 'build_lib',
192
bytecode_outputs = self._bytecode_filenames(pure_outputs)
194
bytecode_outputs = []
197
self._mutate_outputs(self.distribution.has_ext_modules(),
198
'build_ext', 'build_lib',
201
return pure_outputs + bytecode_outputs + ext_outputs
205
def get_inputs (self):
206
"""Get the list of files that are input to this command, ie. the
207
files that get installed as they are named in the build tree.
208
The files in this list correspond one-to-one to the output
209
filenames returned by 'get_outputs()'.
213
if self.distribution.has_pure_modules():
214
build_py = self.get_finalized_command('build_py')
215
inputs.extend(build_py.get_outputs())
217
if self.distribution.has_ext_modules():
218
build_ext = self.get_finalized_command('build_ext')
219
inputs.extend(build_ext.get_outputs())