1
0
mirror of https://github.com/pyenv/pyenv.git synced 2025-11-16 23:33:45 -05:00

import page

Yamashita Yuu
2013-05-18 11:55:35 +09:00
parent b734b8f16d
commit 528564519b

69
Understanding-binstubs.md Normal file

@@ -0,0 +1,69 @@
Binstubs are wrapper scripts around executables (sometimes referred to as
"binaries", although they don't have to be compiled) whose purpose is to prepare
the environment before dispatching the call to the original executable.
In the Python world, the most common binstubs are the ones that setuptools generates
after installing a gem that contains executables. But binstubs can be written in
any language, and it often makes sense to create them manually.
## setuptools
Let's see what happens when we `pip install nose`. [nose ships with an
executable][nosetests]. After the
installation, setuptools will provide us with the following executables:
1. `<python-prefix>/bin/nosetests` (binstub generated by setuptools)
1. `<python-prefix>/lib/python2.7/site-packages/nose/__init__.py` (original)
The first file is a binstub created to wrap the second. setuptools put it in
`<python-prefix>/bin` because that directory is considered to already be in our
`$PATH`.
The directory where setuptools installed the second file (the original) isn't in
our `$PATH`, but even if it was, it wouldn't be safe to run it directly because
executables in Python projects *often aren't meant* to be called directly without
any setup.
The generated binstub `<python-prefix>/bin/nosetests` is a short Python script,
presented in a slightly simplified form here:
```py
#!/usr/bin/env python
# EASY-INSTALL-ENTRY-SCRIPT: 'nose==1.3.0','console_scripts','nosetests'
__requires__ = 'nose==1.3.0'
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.exit(
load_entry_point('nose==1.3.0', 'console_scripts', 'nosetests')()
)
```
The purpose of every setuptools binstub is to use setuptools to prepare the
`sys.path` before calling the original executable.
## pyenv
pyenv adds its own "shims" directory to `$PATH` which contains binstubs for
every executable related to Python. There are binstubs for `python`, `pip`, and for
all setuptools binstubs across each installed Python version.
When you call `rspec` on the command-line, it results in this call chain:
1. `$PYENV_ROOT/shims/rspec` (pyenv shim)
1. `$PYENV_ROOT/versions/2.7.5/bin/nosetests` (setuptools binstub)
1. `$PYENV_ROOT/versions/2.7.5/lib/python2.7/site-packages/nose/__init__.py` (original)
An pyenv shim, presented here in a slightly simplified form, is a short shell script:
```sh
#!/usr/bin/env bash
export PYENV_ROOT="$HOME/.pyenv"
exec pyenv exec "$(basename "$0")" "$@"
```
The purpose of pyenv's shims is to route every call to a python executable through
`pyenv exec`, which ensures it gets executed with the right Python version.