setup.py
(legacy)#
Prior to the introduction of pyproject.toml-based builds (in PEP 517 and
PEP 518), pip had only supported installing packages using setup.py
files
that were built using setuptools.
The interface documented here is retained currently solely for legacy purposes,
until the migration to pyproject.toml
-based builds can be completed.
Caution
The arguments and syntax of the various invocations of setup.py
made by
pip, are considered an implementation detail that is strongly coupled with
setuptools. This build system interface is not meant to be used by any
other build backend, which should be based on the pyproject.toml build
system interface instead.
Further, projects should not expect to rely on there being any form of
backward compatibility guarantees around the setup.py
interface.
Build process#
The overall process for building a package is:
Generate the package’s metadata.
Generate a wheel for the package.
The wheel can then be used to perform an installation, if necessary.
Metadata Generation#
As a first step, pip
needs to get metadata about a package (name, version,
dependencies, and more). It collects this by calling setup.py egg_info
.
The egg_info
command generates the metadata for the package, which pip can
then consume and proceed to gather all the dependencies of the package. Once
the dependency resolution process is complete, pip will proceed to the next
stage of the build process for these packages.
Wheel Generation#
When provided with a source distribution (or “sdist”) for a package, pip will attempt to build a wheel. Since wheel distributions can be cached, this can greatly speed up future installations for the package.
This is done by calling setup.py bdist_wheel
which requires the wheel
package to be installed.
If this wheel generation is successful (this can include compiling C/C++ code, depending on the package), the generated wheel is added to pip’s wheel cache and will be used for this installation. The built wheel is cached locally by pip to avoid repeated identical builds.
If this wheel generation fails, pip runs setup.py clean
to clean up any build
artifacts that may have been generated. After that, pip will attempt a direct
installation.
Editable Installation#
For installing packages in “editable” mode
(pip install --editable), pip will invoke
setup.py develop
, which will use setuptools’ mechanisms to perform an
editable/development installation.
Setuptools Injection#
To support projects that directly use distutils
, pip injects setuptools
into
sys.modules
before invoking setup.py
. This injection should be transparent
to distutils
-based projects.
Customising the build#
The --global-option
and --build-option
arguments to the pip install
and pip wheel
inject additional arguments into the setup.py
command
(--build-option
is only available in pip wheel
).
Attention
The use of --global-option
and --build-option
is highly setuptools
specific, and is considered more an accident of the current implementation than
a supported interface. It is documented here for completeness. These flags will
not be supported, once this build system interface is dropped.
These arguments are included in the command as follows:
python setup.py <global_options> BUILD COMMAND <build_options>
The options are passed unmodified, and presently offer direct access to the distutils command line. For example:
$ python -m pip wheel --global-option bdist_ext --global-option -DFOO wheel
$ python -m pip wheel --global-option bdist_ext --global-option -DFOO wheel
C:> py -m pip wheel --global-option bdist_ext --global-option -DFOO wheel
will result in pip invoking:
setup.py bdist_ext -DFOO bdist_wheel -d TARGET
This passes a preprocessor symbol to the extension build.
Build Output#
Any output produced by the build system will be read by pip (for display to the
user if requested). In order to correctly read the build system output, pip
requires that the output is written in a well-defined encoding, specifically
the encoding the user has configured for text output (which can be obtained in
Python using locale.getpreferredencoding
). If the configured encoding is
ASCII, pip assumes UTF-8 (to account for the behaviour of some Unix systems).
Build systems should ensure that any tools they invoke (compilers, etc) produce
output in the correct encoding. In practice - and in particular on Windows,
where tools are inconsistent in their use of the “OEM” and “ANSI” codepages -
this may not always be possible. pip will therefore attempt to recover cleanly
if presented with incorrectly encoded build tool output, by translating
unexpected byte sequences to Python-style hexadecimal escape sequences
("\x80\xff"
, etc). However, it is still possible for output to be displayed
using an incorrect encoding (mojibake).