1 # created 1999/03/13, Greg Ward
6 from types
import IntType
7 from distutils
.core
import Command
8 from distutils
.errors
import DistutilsOptionError
9 from distutils
.dir_util
import copy_tree
11 class install_lib (Command
):
13 description
= "install all Python modules (extensions and pure Python)"
15 # The byte-compilation options are a tad confusing. Here are the
17 # 1) no compilation at all (--no-compile --no-optimize)
18 # 2) compile .pyc only (--compile --no-optimize; default)
19 # 3) compile .pyc and "level 1" .pyo (--compile --optimize)
20 # 4) compile "level 1" .pyo only (--no-compile --optimize)
21 # 5) compile .pyc and "level 2" .pyo (--compile --optimize-more)
22 # 6) compile "level 2" .pyo only (--no-compile --optimize-more)
24 # The UI for this is two option, 'compile' and 'optimize'.
25 # 'compile' is strictly boolean, and only decides whether to
26 # generate .pyc files. 'optimize' is three-way (0, 1, or 2), and
27 # decides both whether to generate .pyo files and what level of
28 # optimization to use.
31 ('install-dir=', 'd', "directory to install to"),
32 ('build-dir=','b', "build directory (where to install from)"),
33 ('force', 'f', "force installation (overwrite existing files)"),
34 ('compile', 'c', "compile .py to .pyc [default]"),
35 ('no-compile', None, "don't compile .py files"),
37 "also compile with optimization: -O1 for \"python -O\", "
38 "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
39 ('skip-build', None, "skip the build steps"),
42 boolean_options
= ['force', 'compile', 'skip-build']
43 negative_opt
= {'no-compile' : 'compile'}
46 def initialize_options (self
):
47 # let the 'install' command dictate our installation directory
48 self
.install_dir
= None
53 self
.skip_build
= None
55 def finalize_options (self
):
57 # Get all the information we need to install pure Python modules
58 # from the umbrella 'install' command -- build (source) directory,
59 # install (target) directory, and whether to compile .py files.
60 self
.set_undefined_options('install',
61 ('build_lib', 'build_dir'),
62 ('install_lib', 'install_dir'),
64 ('compile', 'compile'),
65 ('optimize', 'optimize'),
66 ('skip_build', 'skip_build'),
69 if self
.compile is None:
71 if self
.optimize
is None:
74 if type(self
.optimize
) is not IntType
:
76 self
.optimize
= int(self
.optimize
)
77 assert 0 <= self
.optimize
<= 2
78 except (ValueError, AssertionError):
79 raise DistutilsOptionError
, "optimize must be 0, 1, or 2"
83 # Make sure we have built everything we need first
86 # Install everything: simply dump the entire contents of the build
87 # directory to the installation directory (that's the beauty of
88 # having a build directory!)
89 outfiles
= self
.install()
91 # (Optionally) compile .py to .pyc
92 if outfiles
is not None and self
.distribution
.has_pure_modules():
93 self
.byte_compile(outfiles
)
98 # -- Top-level worker functions ------------------------------------
99 # (called from 'run()')
102 if not self
.skip_build
:
103 if self
.distribution
.has_pure_modules():
104 self
.run_command('build_py')
105 if self
.distribution
.has_ext_modules():
106 self
.run_command('build_ext')
109 if os
.path
.isdir(self
.build_dir
):
110 outfiles
= self
.copy_tree(self
.build_dir
, self
.install_dir
)
112 self
.warn("'%s' does not exist -- no Python modules to install" %
117 def byte_compile (self
, files
):
118 from distutils
.util
import byte_compile
120 # Get the "--root" directory supplied to the "install" command,
121 # and use it as a prefix to strip off the purported filename
122 # encoded in bytecode files. This is far from complete, but it
123 # should at least generate usable bytecode in RPM distributions.
124 install_root
= self
.get_finalized_command('install').root
127 byte_compile(files
, optimize
=0,
130 verbose
=self
.verbose
, dry_run
=self
.dry_run
)
131 if self
.optimize
> 0:
132 byte_compile(files
, optimize
=self
.optimize
,
135 verbose
=self
.verbose
, dry_run
=self
.dry_run
)
138 # -- Utility methods -----------------------------------------------
140 def _mutate_outputs (self
, has_any
, build_cmd
, cmd_option
, output_dir
):
145 build_cmd
= self
.get_finalized_command(build_cmd
)
146 build_files
= build_cmd
.get_outputs()
147 build_dir
= getattr(build_cmd
, cmd_option
)
149 prefix_len
= len(build_dir
) + len(os
.sep
)
151 for file in build_files
:
152 outputs
.append(os
.path
.join(output_dir
, file[prefix_len
:]))
158 def _bytecode_filenames (self
, py_filenames
):
160 for py_file
in py_filenames
:
162 bytecode_files
.append(py_file
+ "c")
163 if self
.optimize
> 0:
164 bytecode_files
.append(py_file
+ "o")
166 return bytecode_files
169 # -- External interface --------------------------------------------
170 # (called by outsiders)
172 def get_outputs (self
):
173 """Return the list of files that would be installed if this command
174 were actually run. Not affected by the "dry-run" flag or whether
175 modules have actually been built yet.
178 self
._mutate
_outputs
(self
.distribution
.has_pure_modules(),
179 'build_py', 'build_lib',
182 bytecode_outputs
= self
._bytecode
_filenames
(pure_outputs
)
184 bytecode_outputs
= []
187 self
._mutate
_outputs
(self
.distribution
.has_ext_modules(),
188 'build_ext', 'build_lib',
191 return pure_outputs
+ bytecode_outputs
+ ext_outputs
195 def get_inputs (self
):
196 """Get the list of files that are input to this command, ie. the
197 files that get installed as they are named in the build tree.
198 The files in this list correspond one-to-one to the output
199 filenames returned by 'get_outputs()'.
203 if self
.distribution
.has_pure_modules():
204 build_py
= self
.get_finalized_command('build_py')
205 inputs
.extend(build_py
.get_outputs())
207 if self
.distribution
.has_ext_modules():
208 build_ext
= self
.get_finalized_command('build_ext')
209 inputs
.extend(build_ext
.get_outputs())