Add support for Python 3.13 free-threaded build

I'm currently working on adding support for the Python 3.13 free-threaded build to projects in the scientific python ecosystem. We are tracking this work at https://github.com/Quansight-Labs/free-threaded-compatibility. Right now we're focusing on projects relatively low in the stack. scikit-learn isn't the lowest in the stack but it has a lot of tests that perform multithreaded workflows so running the scikit-learn tests is a productive way to elucidate threading bugs in scikit-learn and its dependencies.

Currently, scikit-learn builds fine and almost all the tests pass with the GIL disabled 🎉 

The following tests have failures:

<details>

```
FAILED sklearn/ensemble/tests/test_voting.py::test_sample_weight[42] - AssertionError:
FAILED sklearn/model_selection/tests/test_search.py::test_random_search_cv_results_multimetric - AssertionError:
FAILED sklearn/semi_supervised/tests/test_self_training.py::test_classification[threshold-base_estimator1] - AssertionError:
FAILED sklearn/semi_supervised/tests/test_self_training.py::test_classification[k_best-base_estimator1] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_matrix-linear-X_train0-y_train0-X_test0] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_matrix-linear-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_matrix-linear-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_matrix-poly-X_train0-y_train0-X_test0] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_matrix-poly-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_matrix-poly-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_matrix-rbf-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_matrix-rbf-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_matrix-sigmoid-X_train0-y_train0-X_test0] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_matrix-sigmoid-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_matrix-sigmoid-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_array-linear-X_train0-y_train0-X_test0] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_array-linear-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_array-linear-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_array-poly-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_array-poly-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_array-rbf-X_train0-y_train0-X_test0] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_array-rbf-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_array-rbf-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_array-sigmoid-X_train0-y_train0-X_test0] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_array-sigmoid-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[csr_array-sigmoid-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_matrix-linear-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_matrix-linear-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_matrix-poly-X_train0-y_train0-X_test0] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_matrix-poly-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_matrix-poly-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_matrix-rbf-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_matrix-rbf-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_matrix-sigmoid-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_matrix-sigmoid-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_array-linear-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_array-linear-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_array-poly-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_array-poly-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_array-rbf-X_train0-y_train0-X_test0] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_array-rbf-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_array-rbf-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_array-sigmoid-X_train2-y_train2-X_test2] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_svc[lil_array-sigmoid-X_train3-y_train3-X_test3] - AssertionError:
FAILED sklearn/svm/tests/test_sparse.py::test_consistent_proba - AssertionError:
FAILED sklearn/svm/tests/test_svm.py::test_libsvm_iris - AssertionError:
FAILED sklearn/svm/tests/test_svm.py::test_svc_clone_with_callable_kernel - AssertionError:
FAILED sklearn/svm/tests/test_svm.py::test_consistent_proba - AssertionError:
FAILED sklearn/tests/test_build.py::test_openmp_parallelism_enabled - AssertionError:
FAILED sklearn/tests/test_pipeline.py::test_pipeline_memory - AssertionError:
```

</details>

Note that some of these failures are flaky and you may not get the same list if you run the scikit-learn tests. I also saw one deadlock in `test_calibration.py::test_parallel_execution`, so I'd also suggest running pytest with e.g. `-o fauthandler_timeout=60` set so you will get python tracebacks for all threads if any test hangs and runs longer than 60 seconds. Your mileage may vary on how fast your computer is, so 60 seconds may not be sufficient if any tests take that long to run on your system.

My plan is to go through these failures and figure out what's going wrong. Some of these may not be specific to the free-threaded build.

To run the tests with the GIL disabled, you'll need to install 3.13b1 or the latest version of the CPython 3.13 branch, build cython, numpy, and scipy from the latest version of their respective git repositories. You'll need to e.g. `pip install` pybind11 and pythran after installing numpy and before building scipy. Then build scikit-learn as an editable install and run:

```
PYTHON_GIL=0 python -m pytest sklearn
```

COMMENT:
I tried again, not sure what I did differently this time to be honest, but it went a bit further. This time, I get a build error in numpy `error: unknown type name ‘__pyx_vectorcallfunc’; did you mean ‘vectorcallfunc’?` ...

<details>

<summary>More details</summary>

```
  FAILED: numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/meson-generated_numpy_random__mt19937.pyx.c.o
  ccache cc -Inumpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p -Inumpy/random -I../numpy/random -I../numpy/random/src -Inumpy/_core -I../numpy/_core -Inumpy/_core/include -I../numpy/_core/include -I../numpy/_core/src/common -Inumpy -I/opt/python-free-threading/include/python3.13td -I/home/lesteve/dev/numpy/.mesonpy-2arbmkr6/meson_cpu -fvisibility=hidden -fdiagnostics-color=always -DNDEBUG -Wall -Winvalid-pch -std=c11 -O3 -fno-strict-aliasing -msse -msse2 -msse3 -DNPY_HAVE_SSE2 -DNPY_HAVE_SSE -DNPY_HAVE_SSE3 -fPIC -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -DNPY_NO_DEPRECATED_API=0 -MD -MQ numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/meson-generated_numpy_random__mt19937.pyx.c.o -MF numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/meson-generated_numpy_random__mt19937.pyx.c.o.d -o numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/meson-generated_numpy_random__mt19937.pyx.c.o -c numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/numpy/random/_mt19937.pyx.c
  numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/numpy/random/_mt19937.pyx.c:2380:80: error: unknown type name ‘__pyx_vectorcallfunc’; did you mean ‘vectorcallfunc’?
   2380 | static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw);
        |                                                                                ^~~~~~~~~~~~~~~~~~~~
        |                                                                                vectorcallfunc
  numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/numpy/random/_mt19937.pyx.c:11238:69: error: unknown type name ‘__pyx_vectorcallfunc’; did you mean ‘vectorcallfunc’?
  11238 | static PyObject *__Pyx_PyVectorcall_FastCallDict_kw(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw)
        |                                                                     ^~~~~~~~~~~~~~~~~~~~
        |                                                                     vectorcallfunc
  numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/numpy/random/_mt19937.pyx.c:11283:80: error: unknown type name ‘__pyx_vectorcallfunc’; did you mean ‘vectorcallfunc’?
  11283 | static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw)
        |                                                                                ^~~~~~~~~~~~~~~~~~~~
        |                                                                                vectorcallfunc
  numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/numpy/random/_mt19937.pyx.c: In function ‘__Pyx_CyFunction_CallAsMethod’:
  numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/numpy/random/_mt19937.pyx.c:11972:6: error: unknown type name ‘__pyx_vectorcallfunc’; did you mean ‘vectorcallfunc’?
  11972 |      __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc);
        |      ^~~~~~~~~~~~~~~~~~~~
        |      vectorcallfunc
  numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/numpy/random/_mt19937.pyx.c:2470:45: error: initialization of ‘int’ from ‘vectorcallfunc’ {aka ‘struct _object * (*)(struct _object *, struct _object * const*, long unsigned int,  struct _object *)’} makes integer from pointer without a cast [-Wint-conversion]
   2470 | #define __Pyx_CyFunction_func_vectorcall(f) (((PyCFunctionObject*)f)->vectorcall)
        |                                             ^
  numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/numpy/random/_mt19937.pyx.c:11972:32: note: in expansion of macro ‘__Pyx_CyFunction_func_vectorcall’
  11972 |      __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc);
        |                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/numpy/random/_mt19937.pyx.c:11975:16: error: implicit declaration of function ‘__Pyx_PyVectorcall_FastCallDict’; did you mean ‘__Pyx_PyObject_FastCallDict’? [-Wimplicit-function-declaration]
  11975 |         return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw);
        |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        |                __Pyx_PyObject_FastCallDict
  numpy/random/_mt19937.cpython-313td-x86_64-linux-gnu.so.p/numpy/random/_mt19937.pyx.c:11975:16: error: returning ‘int’ from a function with return type ‘PyObject *’ {aka ‘struct _object *’} makes pointer from integer without a cast [-Wint-conversion]
  11975 |         return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw);
        |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  [502/610] Compiling C++ object numpy/_core/_multiarray_umath.cpython-313td-x86_64-linux-gnu.so.p/src_umath_stringdtype_ufuncs.cpp.o
  In file included from ../numpy/_core/src/umath/stringdtype_ufuncs.cpp:21:
  ../numpy/_core/src/umath/string_buffer.h:265:23: warning: template-id not allowed for constructor in C++20 [-Wtemplate-id-cdtor]
    265 |     inline Buffer<enc>()
        |                       ^
  ../numpy/_core/src/umath/string_buffer.h:265:23: note: remove the ‘< >’
  ../numpy/_core/src/umath/string_buffer.h:270:23: warning: template-id not allowed for constructor in C++20 [-Wtemplate-id-cdtor]
    270 |     inline Buffer<enc>(char *buf_, npy_int64 elsize_)
        |                       ^
  ../numpy/_core/src/umath/string_buffer.h:270:23: note: remove the ‘< >’
  [503/610] Compiling C object numpy/_core/_multiarray_umath.cpython-313td-x86_64-linux-gnu.so.p/meson-generated_lowlevel_strided_loops.c.o
  [504/610] Compiling C object numpy/_core/_multiarray_umath.cpython-313td-x86_64-linux-gnu.so.p/src_umath_ufunc_object.c.o
  [505/610] Compiling C++ object numpy/_core/_multiarray_umath.cpython-313td-x86_64-linux-gnu.so.p/src_npysort_selection.cpp.o
  [506/610] Compiling C++ object numpy/_core/_multiarray_umath.cpython-313td-x86_64-linux-gnu.so.p/src_npysort_quicksort.cpp.o
  [507/610] Compiling C++ object numpy/_core/_multiarray_umath.cpython-313td-x86_64-linux-gnu.so.p/src_umath_string_ufuncs.cpp.o
  In file included from ../numpy/_core/src/umath/string_ufuncs.cpp:21:
  ../numpy/_core/src/umath/string_buffer.h:265:23: warning: template-id not allowed for constructor in C++20 [-Wtemplate-id-cdtor]
    265 |     inline Buffer<enc>()
        |                       ^
  ../numpy/_core/src/umath/string_buffer.h:265:23: note: remove the ‘< >’
  ../numpy/_core/src/umath/string_buffer.h:270:23: warning: template-id not allowed for constructor in C++20 [-Wtemplate-id-cdtor]
    270 |     inline Buffer<enc>(char *buf_, npy_int64 elsize_)
        |                       ^
  ../numpy/_core/src/umath/string_buffer.h:270:23: note: remove the ‘< >’


</details>

Labels: Enhancement, Build / CI, free-threading