Open AllSeeingEyeTolledEweSew opened 3 years ago
Thank you for your contributions. Main development of B2 has moved to https://github.com/bfgroup/b2 This issue has been automatically marked as "transition" to indicate the potential for needing transition to the new B2 development project.
I'm working on libtorrent's python bindings and I'm finding that it's really difficult to package and test
b2
python targets using python ecosystem standards.Python extensions are normally built by
distutils
, which always builds them against the running python interpreter. That is, if you build usingpython3.6 setup.py bdist_wheel
, you'll get a wheel build against thepython3.6
you ran.This dovetails with the standard python package testing workflow, which looks like this:
Note that
distutils
'bdist_wheel
is actually the only standard tooling to create python wheels. So if you want to package a python target fromb2
into a wheel, the most straightforward way is to write asetup.py
, and customize itsbuild_ext
step to invokeb2
instead of building usingdistutils
logic.So for both packaging and testing, we need to get
b2
to follow the python practice of build for a given interpreter. Butb2
's design makes this hard.We can try
b2 python=X.Y
, but we need to ensure this matches someusing python : X.Y : ...
in some*-config.jam
, which matches our given environment and not others, and isn't overridden by any other config.The problem is that
b2
treats python likegcc
, as some tool installed globally by a supervisor in one or more versions. But this is not how python works. Local, temporary virtual environments are the rule, not the exception. We certainly can't rely on~/user-config.jam
to have what we need.In libtorrent, I ended up having
setup.py
create a temporaryproject-config.jam
like this:Then,
setup.py
invokesb2 python=X.Y libtorrent-python=on ...
. The dummylibtorrent-python
feature lets me select only my dynamically-created python configuration.We're only halfway done, because we can't trust
python.jam
's other configuration guesses.I believe the code that guesses include and library search paths has never been tested in virtual environments. It doesn't honor the difference between
sys.exec_prefix
andsys.base_exec_prefix
.Worse than just being wrong on some platforms, the guesses appear kind of willy-nilly. For instance, it applies a
"pythonX.Y/config"
library search path on all non-windows platforms, but this appears to only be appropriate for cygwin.Worse, the python config rule only allows a single library search path. There are certainly cases where we need multiple ones. I ended up resolving this by adding extra
library-path=...
requirements to myb2
command. It's not really appropriate to apply these globally, but I couldn't think of another solution.distutils
also has code that guesses include and library paths, and it does a much better job. For our autogenerated python config, we override include and library paths with theinclude_dirs
andlibrary_dirs
attributes ofdistutils.command.build_ext.build_ext
. In case these are empty, I do not trustpython.jam
's guesses not to be destructive, and I configure garbage search paths instead.Finally, we want our
build_ext
to produce an artifact with name and location it normally would, so otherdistutils
logic can consume it.python.jam
is unhelpful again here, as its configuration guesses aren't helpful and it appends a platform-specific suffix to whatever was configured. So if we get a correct value fromdistutils
, we must anticipatepython.jam
's mangling and de-mangle our value correctly.I think in the short term:
b2 python.exe=/path/to/my/pythonX.Y
*-config.jam
build_ext
withindistutils
python.jam
's existing library and include search path guesses should be correct for virtual environments, on all platformsIn the long term, I think the boost team should come up with a more clear story for how a user can use
b2
python targets with standard python tools, and package them in standard ways. This was way too much work.