Gentoo Archives: gentoo-dev

From: Brian Harring <ferringb@×××××.com>
To: gentoo-dev@l.g.o
Cc: python@g.o
Subject: [gentoo-dev] reworking python-wrapper and wrapper scripts.
Date: Thu, 18 Oct 2012 09:16:34
Message-Id: 20121018091543.GA2692@localhost.corp.google.com
1 If folks haven't looked at python_generate_wrapper_scripts in
2 python.eclass, I'd suggest doing so. For examples of it's usage, grep
3 for 'python_generate_wrapper_scripts' in /usr/bin/; any place you see
4 it, look for <that-script-name>-${PYTHON_TARGETS} (for example,
5 /usr/bin/sphinx-build{,-2.7,-3.2}.
6
7 Each usage there is a separate custom script for that specific binary;
8 if there is a bug in the script, well, we're screwed- requires
9 re-merging the package.
10
11 This setup, at least on my hardware, is .04s added to every
12 invocation; this is ignoring the inode cost for each, and the issue if
13 a bug ever appears in the script generation code (in which case we're
14 screwed- would require re-merging the package).
15
16 In parallel, we've got python-wrapper (ls /usr/bin/python -l); this is
17 provided by eselect-python and basically discern what the active
18 python version is, and use that in the absense of any directives.
19 This is implemented in C, and is reasonably sane; the overhead for
20 that is basically non-existant.
21
22 Roughly, I'm proposing we do away with python eclass's
23 generate_python_wrapper_scripts generation of a script, instead having
24 that just symlink to a binary provided by eselect-python that handles
25 this. This centralizes the implementation (fix in one spot), and
26 would allow a c version to be used- basically eliminating the
27 overhead.
28
29
30 There's a trick to this; currently, those generated scripts hardcode
31 the allowed/known python versions for that package. We obviously have
32 to preserve that; I propose we shove it into the symlink path.
33
34 Basically, we add a /usr/libexec/python directory; within it, we have
35 a wrapper binary (explained below), and a set of symlinks pointing at
36 the root of that directory. To cover our current python versions, the
37 following would suffice:
38
39 for x in {2.{4,5,6,7},3.{0,1,2,3,4}}-cpy 2.5-jython 2.7-pypy-1.{7,8}
40 \2.7-pypy-1.9; do
41 ln -s ./ /usr/libexec/python/$x
42 done
43
44 While that seems insane, there is a reason; via that, we can encode
45 the allowed versions into the symlink. Using pkgcore's pquery for
46 example (which should support cpy: 2.5, 2.6, 2.7, 3.1, 3.2, 3.3)
47 instead of a wrapper script at /usr/bin/pquery, we'd have thus:
48
49 targets=( 2.{5,6,7}-cpy 3.{1,2,3}-cpy )
50 targets=$(IFS=/;echo -n "${targets[*]}")
51 # This results in
52 # targets=2.5-cpy/2.6-cpy/2.7-cpy/3.1-cpy/3.2-cpy/3.3-cpy
53 ln -s "/usr/libexec/python/${targets}/wrapper" \
54 /usr/bin/pquery
55
56 /usr/libexec/python/wrapper upon invocation, takes a look at argv[0];
57 sees how it was invoked basically. This will be the /usr/bin/whatever
58 pathway. It reads the symlink, in the process getting the allowed
59 versions and preferred order of the versions.
60
61 Few notes; vast majority of filesystems will store the symlink target
62 into the core inode if at all possible- in doing so, this avoids
63 wasting an inode and is only limited by the length of the target.
64 That length is capped by PATH_MAX- which can range from 256 to 4k (or
65 higher).
66
67 For the pquery example above, that comes out to ~73 bytes for the
68 symlink pathway; well under PATH_MAX.
69
70 For the scenarios where PATH_MAX caps the symlink pathway, or for
71 whatever reason we don't want to use that trick, a tree of files
72 contained within /usr/libexec/python/ holding the allowed versions for
73 the matching pathway would suffice.
74
75 Either proposal here would be far faster than what we've got now; also
76 will use less space (ancillary benefit).
77
78 One subtle aspect here is that if we did this, it makes it possible to
79 avoid losing the invocation information- currently if you did
80 `/usr/bin/python3.2 $(which sphinx-build) blah`, because of how things
81 are implemented now (specifically the two layers of wrappers)- you'll
82 get python2.7 running that sphinx-build invocation.
83
84 This is wrong (it's directly discarding what the invocation
85 requested), although you're only going to see it for scripts that
86 do python introspection.
87
88 Via doing the restructuring I'm mentioning above, that issue can be
89 fixed, while making things faster/saner.
90
91 On a related note; we currently install multiple versions of the same
92 script- the only difference being the shebang. If one ignores the
93 shebang, in some cases this is necessary- where the script is 2to3
94 translated, and the code for py2k vs py3k differs. For most, the only
95 difference is in the shebang however.
96
97 While it's minor in space savings, it's possible to eliminate that
98 redundancy via a shebang target that looks at the pathway it was
99 invoked via. Fairly easy actually, and basically zero overhead if
100 done.
101
102 Either way, thoughts?
103
104 What I'm proposing isn't perfect, but I'm of the view it's a step up
105 from what's in place now- and via centralizing this crap, makes it
106 easier to change/maintain this going forward as necessary.
107 ~harring

Replies