Skip to content

Commit

Permalink
Add FAQ with common errors and how to deal with them (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
ngoldbaum authored Jul 26, 2024
1 parent ccb5198 commit b580d28
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 0 deletions.
97 changes: 97 additions & 0 deletions docs/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,101 @@ by `gdb`/`lldb` at the moment of debugging. For more information regarding
CPython installation sources, please visit the
[Installing a free-threaded Python](installing_cpython.md) page.

## Frequently seen errors and how to fix them

These are error messages that we see come up often when working with code or
development workflows that have not been updated to accommodate the
free-threaded build. We also provide suggested fixes. Please send in pull
requests to [the repository for this
document](https://github.com/quansight-labs/free-threaded-compatibility) if you
run into any confusing free-threading-specific errors that you suspect apply to
other libraries and aren't covered here.

### Cython compilation errors: `unknown type name '__pyx_vectorcallfunc'`

This happens if you try to build a Cython extension for the free-threaded build
using the current stable release of Cython (3.0.10 at the time of writing). The
current stable release of Cython does not support the free-threaded build. You
must either build Cython from the `master` branch [on
Github](https://github.com/cython/cython) or use the nightly wheel:

```bash
pip install -i https://pypi.anaconda.org/scientific-python-nightly-wheels/simple cython
```

See [the porting guide](porting.md) for more detail about porting Cython code to
work under free-threading.

You may wonder why you are able to install a wheel for the current Cython
release at all. This is because Cython ships a pure-python wheel tagged with
`py2.py3-none-any`, which pip will install if it cannot find another wheel that
is compatible. A future version of Cython will ship a wheel with compiled code
that supports the free-threaded build.

The current nightly wheel is a pure-python build, so it works on all
architectures. The pure-python version of Cython is usually only marginally
slower than a compiled version, so you should default to installing the wheel in
CI instead of compiling Cython, which can take up to a few minutes on some CI
runners.

### Cython compilation errors arising from `static_assert`

This error arises from a limitation in Cython that exposes a CPython
implementation detail. Under clang, the issue manifests in error messages like
the following example, generated by building scikit-learn with a C99 compilation
environment:

```
In file included from sklearn/__check_build/_check_build.cpython-313t-darwin.so.p/sklearn/__check_build/_check_build.pyx.c:4315:
In file included from /path/to/python/3.13.0b3t/include/python3.13t/internal/pycore_frame.h:13:
/path/to/python/3.13.0b3t/include/python3.13t/internal/pycore_code.h:537:15: error: expected parameter declarator
static_assert(COLD_EXIT_INITIAL_VALUE > ADAPTIVE_COOLDOWN_VALUE,
^
/path/to/python/3.13.0b3t/include/python3.13t/internal/pycore_backoff.h:125:33: note: expanded from macro 'COLD_EXIT_INITIAL_VALUE'
#define COLD_EXIT_INITIAL_VALUE 64
^
In file included from sklearn/__check_build/_check_build.cpython-313t-darwin.so.p/sklearn/__check_build/_check_build.pyx.c:4315:
In file included from /path/to/python/3.13.0b3t/include/python3.13t/internal/pycore_frame.h:13:
/path/to/python/3.13.0b3t/include/python3.13t/internal/pycore_code.h:537:15: error: expected ')'
/path/to/python/3.13.0b3t/include/python3.13t/internal/pycore_backoff.h:125:33: note: expanded from macro 'COLD_EXIT_INITIAL_VALUE'
#define COLD_EXIT_INITIAL_VALUE 64
^
/path/to/python/3.13.0b3t/include/python3.13t/internal/pycore_code.h:537:14: note: to match this '('
static_assert(COLD_EXIT_INITIAL_VALUE > ADAPTIVE_COOLDOWN_VALUE,
^
/path/to/python/3.13.0b3t/include/python3.13t/internal/pycore_code.h:537:1: error: type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int [-Wimplicit-int]
static_assert(COLD_EXIT_INITIAL_VALUE > ADAPTIVE_COOLDOWN_VALUE,
^
int
```

Free-threading support in Cython relies CPython internals. In particular, Cython
will generate code that in some situations includes an internal CPython header,
`pycore_frame.h`. This header, in turn, includes another header `pycore_code.h`
that makes use of `static_assert`, a construct defined in the C11 standard. This
is problematic for a compiler assuming compliance with C99.

In practice we have found the easiest way to fix this is to update the standard
used to build C code to either C11 or C17. In the meson build configuration for
a simple C project, this looks like:

```meson
project(
'my-project',
'c',
default_options: [
'c_std=c17',
],
)
```

Note that C17 corrected defects, removed optional requirements, and did not add
any new features compared with C11, so requiring C11 support may be more onerous than
C17. The CPython codebase currently assumes a compiler with at least partial C11
support, and we have found for all major compilers (including MSVC) that
updating the assumed C standard is not a big problem as of mid-2024. There are
some C11 features that MSVC and other compilers are missing, so please open an
issue if this ends up being a big problem for your project or a subset of your
userbase.

[^1]: This feature is not correctly working on `lldb` after CPython 3.12.
8 changes: 8 additions & 0 deletions docs/porting.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ after importing a module that does not support the GIL.
endif
```

In CI, you will need to ensure a nightly cython is installed for
free-threaded builds and disable build isolation by passing
`--no-build-isolation` to `pip` at build time. If you
use `cibuildwheel` to produce wheels, you can conditionally set
`CIBW_BUILD_FRONTEND` to `build; args: --no-build-isolation` for free-threaded
builds. If your project normally uses `pip` to build wheels, the variable
should be set to `pip; args --no-build-isolation`.

=== "f2py"
Starting with NumPy 2.1.0 (only available via the nightly wheels or the
`main` branch as of right now), extension modules containing f2py-wrapped
Expand Down

0 comments on commit b580d28

Please sign in to comment.