This resolves #2189.

> build isolation would be a bit difficult to use in our case, as for instance when building scipy we need the patched numpy on the host and not the numpy version specified in pyproject.toml (which would be unpatched)

This is indeed the case, certain packages cannot be isolated. My strategy is to make a list of packages that shouldn't be isolated and add symlinks from the isolated build environment into the `.artifacts` directory to "unisolate" them. Then we remove the unisolated package requirements from the list of packages to install, in case pesky constraints aren't satisfied. In particular, packages that expect to be used with `pypa/build` often feel free to put very specific constraints on their build dependencies (often asking them to be == to a particular version). Specific version constraints is good for build reproducibility and with build isolation doesn't cost anything. So we just ignore the constraints. Hopefully nothing goes wrong.

In particular, any package that does stuff both at build time and at runtime and requires synchronization between the build time and run time environments needs the unisolation. This includes cffi with `_cffi_backend.so`, and of course numpy and scipy. pycparser needs to be unisolated because it is a dependency of cffi.

Currently I have also unisolated pythran and cython, though these are build time only tools and do not really need to be unisolated. Cython I unisolated specifically because numcodecs needs it but it isn't in the numcodecs build dependencies. Pythran I unisolated because of a problem with the scipy build which I don't fully understand (some problem with long double feature detection). I believe both of these are removable, particularly once #2132 is finished.
Use pypa/build. This resolves #2189.

> build isolation would be a bit difficult to use in our case, as for instance when building scipy we need the patched numpy on the host and not the numpy version specified in pyproject.toml (which would be unpatched)

This is indeed the case, certain packages cannot be isolated. My strategy is to make a list of packages that shouldn't be isolated and add symlinks from the isolated build environment into the `.artifacts` directory to "unisolate" them. Then we remove the unisolated package requirements from the list of packages to install, in case pesky constraints aren't satisfied. In particular, packages that expect to be used with `pypa/build` often feel free to put very specific constraints on their build dependencies (often asking them to be == to a particular version). Specific version constraints is good for build reproducibility and with build isolation doesn't cost anything. So we just ignore the constraints. Hopefully nothing goes wrong.

In particular, any package that does stuff both at build time and at runtime and requires synchronization between the build time and run time environments needs the unisolation. This includes cffi with `_cffi_backend.so`, and of course numpy and scipy. pycparser needs to be unisolated because it is a dependency of cffi.

Currently I have also unisolated pythran and cython, though these are build time only tools and do not really need to be unisolated. Cython I unisolated specifically because numcodecs needs it but it isn't in the numcodecs build dependencies. Pythran I unisolated because of a problem with the scipy build which I don't fully understand (some problem with long double feature detection). I believe both of these are removable, particularly once #2132 is finished.
# This file gets copied into the Modules/ folder when building
# newlib configurations which do not support dynamic library
# loading.
#
# See build/Python-*/Modules/Setup for more details

*static*

array arraymodule.c	# array objects
audioop audioop.c	# Operations on audio samples
math mathmodule.c _math.c # -lm # math library functions, e.g. sin()
cmath cmathmodule.c # complex math functions
_contextvars _contextvarsmodule.c
_struct _struct.c	# binary structure packing/unpacking
_random _randommodule.c	# Random number generator
_bisect _bisectmodule.c	# Bisection algorithms
_datetime _datetimemodule.c
_heapq _heapqmodule.c
_json _json.c
_csv _csv.c

CTYPES_FLAGS=-DHAVE_FFI_PREP_CIF_VAR=1 -DHAVE_FFI_PREP_CLOSURE_LOC=1 -DHAVE_FFI_CLOSURE_ALLOC=1
_ctypes _ctypes/_ctypes.c _ctypes/callbacks.c _ctypes/callproc.c _ctypes/cfield.c _ctypes/stgdict.c $(CTYPES_FLAGS)
_ctypes_test _ctypes/_ctypes_test.c

unicodedata unicodedata.c
_pickle _pickle.c

_socket socketmodule.c
select selectmodule.c
_posixsubprocess _posixsubprocess.c
binascii binascii.c

zlib zlibmodule.c

pyexpat expat/xmlparse.c expat/xmlrole.c expat/xmltok.c pyexpat.c -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI -DXML_POOR_ENTROPY

_sha1 sha1module.c
_sha256 sha256module.c
_sha512 sha512module.c
_sha3 _sha3/sha3module.c
_md5 md5module.c
_blake2 _blake2/blake2module.c _blake2/blake2b_impl.c _blake2/blake2s_impl.c

# If we put this directly in the next line, makesetup incorrectly views the
# line as a definition line, instead of specifying a module. We bypass this
# problem by defining an extra variable that contains the =, and this line is
# correctly viewed as a definition line. We need extra quotes to make gcc think
# we want to define MODULE_NAME to be the string "sqlite" instead of the
# abstract symbol sqlite.
SQLITEMODULENAME=MODULE_NAME=\'"sqlite"\'
_sqlite3 _sqlite/cache.c _sqlite/connection.c _sqlite/cursor.c _sqlite/microprotocols.c _sqlite/module.c _sqlite/prepare_protocol.c _sqlite/row.c _sqlite/statement.c _sqlite/util.c -D$(SQLITEMODULENAME) -lsqlite3
_crypt _cryptmodule.c
_bz2 _bz2module.c -lbz2

_queue _queuemodule.c

#future_builtins future_builtins.c

_multibytecodec cjkcodecs/multibytecodec.c

_codecs_cn cjkcodecs/_codecs_cn.c
_codecs_hk cjkcodecs/_codecs_hk.c
_codecs_iso2022 cjkcodecs/_codecs_iso2022.c
_codecs_jp cjkcodecs/_codecs_jp.c
_codecs_kr cjkcodecs/_codecs_kr.c
_codecs_tw cjkcodecs/_codecs_tw.c

_lsprof _lsprof.c rotatingtree.c

_decimal _decimal/_decimal.c _decimal/libmpdec/basearith.c _decimal/libmpdec/constants.c _decimal/libmpdec/context.c _decimal/libmpdec/convolute.c _decimal/libmpdec/crt.c _decimal/libmpdec/difradix2.c _decimal/libmpdec/fnt.c _decimal/libmpdec/fourstep.c _decimal/libmpdec/io.c _decimal/libmpdec/mpalloc.c _decimal/libmpdec/mpdecimal.c _decimal/libmpdec/numbertheory.c _decimal/libmpdec/sixstep.c _decimal/libmpdec/transpose.c -I$(srcdir)/Modules/_decimal/libmpdec
mmap mmapmodule.c
_xxsubinterpreters _xxsubinterpretersmodule.c

# This file gets copied into the Modules/ folder when building
# newlib configurations which do not support dynamic library
# loading.
#
# See build/Python-*/Modules/Setup for more details

*static*

array arraymodule.c	# array objects
audioop audioop.c	# Operations on audio samples
math mathmodule.c _math.c # -lm # math library functions, e.g. sin()
cmath cmathmodule.c # complex math functions
_contextvars _contextvarsmodule.c
_struct _struct.c	# binary structure packing/unpacking
_random _randommodule.c	# Random number generator
_bisect _bisectmodule.c	# Bisection algorithms
_datetime _datetimemodule.c
_heapq _heapqmodule.c
_json _json.c
_csv _csv.c

CTYPES_FLAGS=-DHAVE_FFI_PREP_CIF_VAR=1 -DHAVE_FFI_PREP_CLOSURE_LOC=1 -DHAVE_FFI_CLOSURE_ALLOC=1
_ctypes _ctypes/_ctypes.c _ctypes/callbacks.c _ctypes/callproc.c _ctypes/cfield.c _ctypes/stgdict.c $(CTYPES_FLAGS)
_ctypes_test _ctypes/_ctypes_test.c

unicodedata unicodedata.c
_pickle _pickle.c

_socket socketmodule.c
select selectmodule.c
_posixsubprocess _posixsubprocess.c
binascii binascii.c

zlib zlibmodule.c

pyexpat expat/xmlparse.c expat/xmlrole.c expat/xmltok.c pyexpat.c -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI -DXML_POOR_ENTROPY

_sha1 sha1module.c
_sha256 sha256module.c
_sha512 sha512module.c
_sha3 _sha3/sha3module.c
_md5 md5module.c
_blake2 _blake2/blake2module.c _blake2/blake2b_impl.c _blake2/blake2s_impl.c

# If we put this directly in the next line, makesetup incorrectly views the
# line as a definition line, instead of specifying a module. We bypass this
# problem by defining an extra variable that contains the =, and this line is
# correctly viewed as a definition line. We need extra quotes to make gcc think
# we want to define MODULE_NAME to be the string "sqlite" instead of the
# abstract symbol sqlite.
SQLITEMODULENAME=MODULE_NAME=\'"sqlite"\'
_sqlite3 _sqlite/cache.c _sqlite/connection.c _sqlite/cursor.c _sqlite/microprotocols.c _sqlite/module.c _sqlite/prepare_protocol.c _sqlite/row.c _sqlite/statement.c _sqlite/util.c -D$(SQLITEMODULENAME) -lsqlite3
_crypt _cryptmodule.c
_bz2 _bz2module.c -lbz2

_queue _queuemodule.c

#future_builtins future_builtins.c

_multibytecodec cjkcodecs/multibytecodec.c

_codecs_cn cjkcodecs/_codecs_cn.c
_codecs_hk cjkcodecs/_codecs_hk.c
_codecs_iso2022 cjkcodecs/_codecs_iso2022.c
_codecs_jp cjkcodecs/_codecs_jp.c
_codecs_kr cjkcodecs/_codecs_kr.c
_codecs_tw cjkcodecs/_codecs_tw.c

_lsprof _lsprof.c rotatingtree.c

_decimal _decimal/_decimal.c _decimal/libmpdec/basearith.c _decimal/libmpdec/constants.c _decimal/libmpdec/context.c _decimal/libmpdec/convolute.c _decimal/libmpdec/crt.c _decimal/libmpdec/difradix2.c _decimal/libmpdec/fnt.c _decimal/libmpdec/fourstep.c _decimal/libmpdec/io.c _decimal/libmpdec/mpalloc.c _decimal/libmpdec/mpdecimal.c _decimal/libmpdec/numbertheory.c _decimal/libmpdec/sixstep.c _decimal/libmpdec/transpose.c -I$(srcdir)/Modules/_decimal/libmpdec
mmap mmapmodule.c
_xxsubinterpreters _xxsubinterpretersmodule.c
