On Fri, Jul 7, 2017 at 8:27 PM, Nick Coghlan <ncogh...@gmail.com> wrote:
> The latest round of discussions have been enlightening, as they have
> allowed us to articulate that from pip's point of view, the key
> requirement is to be able to tell a backend not to include anything
> that wouldn't be included when building via an sdist.
>
> From flit's point of view, Tomas wants frontends to able to express a
> preference between two different failure modes:
>
> 1. The frontend wants the wheel build to *guarantee* it exactly
> matches going via the sdist path
> 2. The frontend wants a working wheel build more than it cares about
> matching the sdist path

Both of these are handled neatly by my draft posted at the beginning
of this thread.

OTOH this whole 11th hour discussion of forcing every build system to
have in-tree and out-of-tree build support is solving some other
problem. I'm not entirely sure what that problem is -- I don't think
anyone has articulated it. Your "key requirement" is technically
vacuous -- by definition, *any* correct build backend will only
include the things that would be included when building via an sdist.

Some possible problems that I've seen mentioned in the thread include:

- pip doesn't trust build systems to properly support incremental
builds, so it wants to force it to throw away the build artifacts
after every build
- pip wants to enforce builds going via sdists
- Thomas / Ralf / I are frustrated at the idea of not supporting
incremental builds

But the in-tree/out-of-tree build proposal doesn't address any of
these problems. Part of the support for it seems to be that it
*sounds* like it might somehow provide a compromise between the folks
arguing over what pip should do by default, because it provides a way
of doing incremental builds that kind of looks like pip's current hack
for doing non-incremental builds. But I think this is illusory. We
still have to argue over what pip will actually do by default; all
this does is replace 1 way of doing incremental builds with 2 ways,
and if pip doesn't want to do incremental builds it'll ignore both.

Seriously, what problem is this solving? How can we even have a
discussion about whether it's the best solution when we don't know
that?

In my previous emails I was trying to avoid getting into the
nitty-gritty of actually critiquing the proposal, because I think it's
a fundamental mistake to even try to hash out this kind of complex
design at the last minute; for every issue I think of now there's
probably another one that none of us have noticed yet. But since
everyone else seems so gung-ho to ship this thing without even having
that minimal discussion, here are some concerns and questions:

If we require every project to support both in-tree and out-of-tree
builds, then projects that don't really support out-of-tree builds now
need to implement the copytree hack themselves, and they might get it
wrong. For example, if you don't correctly clear out the old build
tree before copying, your new build could potentially be corrupted by
artifacts from your old build. (I'm having flashbacks to the bug
reports we get on numpy from people who used setup.py install to
upgrade, and because it doesn't uninstall the old version they end up
with some combination of old and new versions overlaid on top of each
other.) This is a whole new potential failure mode that this proposal
is introducing. Is that acceptable?

In fact, I'm guessing that pip will not actually cache build
directories and re-use them, and will only ever supply empty
directories as the out-of-tree build dir. This means that lots of
projects are likely to be released without ever testing their
build-with-a-non-empty-out-of-tree-build-dir path, and thus it won't
work. What are the chances that this turns into another feature that
exists in theory but in practice it rusts over and can't be used,
because trying to do so would break too often?

What happens if a project switches from scons to cmake or vice-versa,
and they get passed a build tree that contains foreign build
artifacts? Are they prepared to detect this and do something sensible?
Traditionally reusing a build context (either an in-place build tree
or an out-of-place build tree) is something that only developers do,
and they do it manually, so this isn't a problem -- you just send an
occasional email to the list saying "hey I just flipped the switch on
the build systems, make sure to do a 'git clean' before your next
build", or people just reflexively do a 'git clean' any time they get
weird results. But now we're proposing to make this a first-class
feature to be used by automatic unsupervised build pipelines; are they
going to end up producing garbage?

Are frontends allowed to move the out-of-tree build directory to
another parent directory? Another filesystem? Another machine? Another
operating system? what do you they have to preserve if they try?
timestamps? inode numbers? (Using inode numbers as part of a change
detection algorithm is a totally reasonable thing for a build system
to do.)

What if a source tree has previously been used for in-place builds, is
this allowed to make future out-of-place builds break? Off the top of
my head I know openssl's build system has an in-place XOR out-of-place
restriction [1]. It looks like CMake is documented to have one as well
[2]. There may be no automatic way to *ever* do a out-of-place build
in a tree that has previously had an in-place build; you might have to
throw out that tree and start over. Is a build system like this
compliant? (Notice from [1] that it sounds like openssl handles this
situation printing a message to the console saying "lol this build is
probably broken idek" and then happily produces a broken build. Notice
from [2] that cmake might randomly decide to do an in-place build even
if you requested an out-of-place build.)

Speaking of which, why do we force backends to support both in-place
and out-of-place? Out-of-place is strictly more powerful (if it works
at all). Why not make that the only mode of operation?

Or: another idea that came up was just passing a flag to the build
backend saying whether the source tree was temporary or not, which has
the advantage that it's clearly defined (pip certainly knows whether
it's going to delete the source tree after it finishes the build), and
potentially side-steps a lot of these problems with managing the
out-of-tree build cache. Would that be better or worse? I don't know
how to answer that given that I don't know what problem we're trying
to solve here.

Is pip planning to enforce that the source directory is left
unmodified? If not, then do we expect that projects will actually skip
modifying the source tree in practice? It's *very* easy to
accidentally break this rule without realizing it. Will this happen
often enough to make this non-viable for whatever we're trying to do
here? (I guess it has something to do with getting trustworthy builds
from untrustworthy build systems, so this seems relevant.)

Does anyone know how widely supported out-of-place builds are *in real
life*? I know that all the major build frameworks have the
infrastructure, but I'm one of those weirdos who habitually does
out-of-place builds whenever I build software by hand, and back when I
used to build a lot of software by hand then it was *very* common for
this mode of operation to be broken due to whatever weird hack used
inside a specific project's build system. It's been ~10 years since I
did that often though; maybe things have gotten better?

------

I'm really not trying to be an asshole here :-(. Being the asshole is
extremely unpleasant, and I just had throw myself in front of the
prepare_build_files train before everyone suddenly realized that
whoops, maybe wasn't as great an idea as they thought. But like...
everyone does understand right that whatever we put in here, we're
stuck with forever? This isn't like some new project where you can
release 0.0.1 and then spend a few years noodling around with the API
before you release 1.0 and start promising backcompat. This is version
0.0.1 and 1.0 at the same time, and also we can't write any tests
until after we release it, and we may never be able to release a 2.0.
(Look at WSGI -- I mean, it's tremendously popular and influential,
obviously they did some things right, but the spec is full of awful
stuff that everyone hates and all its imitators dropped, but fixing it
is impossible.)

I just don't understand how everyone has the confidence that this
proposal is a mature solid thing that will stand the test of time.
Maybe it will! But how can you possibly know that when we haven't even
scratched the surface of all its implications? Shouldn't the
prepare_build_files thing be a clue that your judgement might not be
100% reliable on these things?

And the alternative is just like... go ahead and ship something that
only supports in-place builds directly (e.g. my draft at the top of
this thread), add out-of-place builds later as an optional extension
if it's useful, if the frontend really wants an out-of-place build it
can fall back on shutil.copytree (plus as a bonus it *knows* that the
backend can't make use of the resulting temporary build directory, so
it can throw it away instead of caching it, and there's zero chance of
cross-build pollution). If anything this seems like the end result
would be *superior* to this proposal, and I've seen zero evidence that
out-of-core builds are something we need to solve now.

Can we please just not? I actually have a list of fiddly details that
need to be discussed about the core part of the proposal, but I don't
see how we'll ever get to the point of nailing down these kinds of
details when all the oxygen is going into this kind of proposal whose
implications are too complicated for us to even understand.

>> PEP 517 was written in 2015...
>
> And PEP 426 was written in 2012. Standards development tImelines can
> get looong when the status quo at least kinda sorta works, and nobody
> has commercial deadlines forcing them to push to standardize new
> interfaces before a genuine consensus has developed :)

I humbly suggest that this isn't an immutable fact of nature, but
rather there are strategies that we can adopt intentionally to reduce
the chance of repeating PEP 426's fate. If we want to.

-n

[1] https://mta.openssl.org/pipermail/openssl-dev/2016-June/007364.html
[2] "Note: Before performing an out-of-source build, ensure that all
CMake generated in-source build information is removed" --
https://cmake.org/Wiki/CMake_FAQ#What_is_an_.22out-of-source.22_build.3F

-- 
Nathaniel J. Smith -- https://vorpus.org
_______________________________________________
Distutils-SIG maillist  -  Distutils-SIG@python.org
https://mail.python.org/mailman/listinfo/distutils-sig

Reply via email to