diff --git a/dev-lang/python/patches/python3.12-3.12.0.patchset b/dev-lang/python/patches/python3.12-3.12.0.patchset new file mode 100644 index 000000000..cd1ce78a8 --- /dev/null +++ b/dev-lang/python/patches/python3.12-3.12.0.patchset @@ -0,0 +1,835 @@ +From df5c54613613970c62e0bb947915137a4cba20dc Mon Sep 17 00:00:00 2001 +From: Oscar Lesta +Date: Sun, 8 Oct 2023 01:02:25 -0300 +Subject: initial Haiku patch + +Based on the patch from Jerome Duval, modified to make it apply cleanly +over 3.12's sources. + +Parts of that original patch were split into specific commit/patches. + +diff --git a/Include/pyport.h b/Include/pyport.h +index 35eca72..7dd2f84 100644 +--- a/Include/pyport.h ++++ b/Include/pyport.h +@@ -691,7 +691,7 @@ extern char * _getpty(int *, int, mode_t, int); + # define _Py_FORCE_UTF8_LOCALE + #endif + +-#if defined(_Py_FORCE_UTF8_LOCALE) || defined(__APPLE__) ++#if defined(_Py_FORCE_UTF8_LOCALE) || defined(__APPLE__) || defined(__HAIKU__) + // Use UTF-8 as the filesystem encoding. + // See PyUnicode_DecodeFSDefaultAndSize(), PyUnicode_EncodeFSDefault(), + // Py_DecodeLocale() and Py_EncodeLocale(). +diff --git a/Lib/plat-haiku1/regen b/Lib/plat-haiku1/regen +new file mode 100644 +index 0000000..4372ee2 +--- /dev/null ++++ b/Lib/plat-haiku1/regen +@@ -0,0 +1,4 @@ ++#! /bin/sh ++HEADERS=/boot/develop/headers ++set -v ++eval $PYTHON_FOR_BUILD ../../Tools/scripts/h2py.py -i "'(u_long)'" $HEADERS/posix/netinet/in.h +diff --git a/Makefile.pre.in b/Makefile.pre.in +index 09ceccd..921668a 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -147,7 +147,7 @@ BINDIR= @bindir@ + LIBDIR= @libdir@ + MANDIR= @mandir@ + INCLUDEDIR= @includedir@ +-CONFINCLUDEDIR= $(exec_prefix)/include ++CONFINCLUDEDIR= $(INCLUDEDIR) + PLATLIBDIR= @PLATLIBDIR@ + SCRIPTDIR= $(prefix)/$(PLATLIBDIR) + ABIFLAGS= @ABIFLAGS@ +diff --git a/Modules/resource.c b/Modules/resource.c +index 3c89468..3ea22bf 100644 +--- a/Modules/resource.c ++++ b/Modules/resource.c +@@ -124,6 +124,7 @@ resource_getrusage_impl(PyObject *module, int who) + PyFloat_FromDouble(doubletime(ru.ru_utime))); + PyStructSequence_SET_ITEM(result, 1, + PyFloat_FromDouble(doubletime(ru.ru_stime))); ++#ifndef __HAIKU__ + PyStructSequence_SET_ITEM(result, 2, PyLong_FromLong(ru.ru_maxrss)); + PyStructSequence_SET_ITEM(result, 3, PyLong_FromLong(ru.ru_ixrss)); + PyStructSequence_SET_ITEM(result, 4, PyLong_FromLong(ru.ru_idrss)); +@@ -138,7 +139,22 @@ resource_getrusage_impl(PyObject *module, int who) + PyStructSequence_SET_ITEM(result, 13, PyLong_FromLong(ru.ru_nsignals)); + PyStructSequence_SET_ITEM(result, 14, PyLong_FromLong(ru.ru_nvcsw)); + PyStructSequence_SET_ITEM(result, 15, PyLong_FromLong(ru.ru_nivcsw)); +- ++#else ++ PyStructSequence_SET_ITEM(result, 2, PyLong_FromLong(0)); ++ PyStructSequence_SET_ITEM(result, 3, PyLong_FromLong(0)); ++ PyStructSequence_SET_ITEM(result, 4, PyLong_FromLong(0)); ++ PyStructSequence_SET_ITEM(result, 5, PyLong_FromLong(0)); ++ PyStructSequence_SET_ITEM(result, 6, PyLong_FromLong(0)); ++ PyStructSequence_SET_ITEM(result, 7, PyLong_FromLong(0)); ++ PyStructSequence_SET_ITEM(result, 8, PyLong_FromLong(0)); ++ PyStructSequence_SET_ITEM(result, 9, PyLong_FromLong(0)); ++ PyStructSequence_SET_ITEM(result, 10, PyLong_FromLong(0)); ++ PyStructSequence_SET_ITEM(result, 11, PyLong_FromLong(0)); ++ PyStructSequence_SET_ITEM(result, 12, PyLong_FromLong(0)); ++ PyStructSequence_SET_ITEM(result, 13, PyLong_FromLong(0)); ++ PyStructSequence_SET_ITEM(result, 14, PyLong_FromLong(0)); ++ PyStructSequence_SET_ITEM(result, 15, PyLong_FromLong(0)); ++#endif + if (PyErr_Occurred()) { + Py_DECREF(result); + return NULL; +@@ -387,19 +403,19 @@ resource_exec(PyObject *module) + } + + /* insert constants */ +-#ifdef RLIMIT_CPU ++#if !defined(__HAIKU__) && defined(RLIMIT_CPU) + ADD_INT(module, RLIMIT_CPU); + #endif + +-#ifdef RLIMIT_FSIZE ++#if !defined(__HAIKU__) && defined(RLIMIT_FSIZE) + ADD_INT(module, RLIMIT_FSIZE); + #endif + +-#ifdef RLIMIT_DATA ++#if !defined(__HAIKU__) && defined(RLIMIT_DATA) + ADD_INT(module, RLIMIT_DATA); + #endif + +-#ifdef RLIMIT_STACK ++#if !defined(__HAIKU__) && defined(RLIMIT_STACK) + ADD_INT(module, RLIMIT_STACK); + #endif + +@@ -411,31 +427,31 @@ resource_exec(PyObject *module) + ADD_INT(module, RLIMIT_NOFILE); + #endif + +-#ifdef RLIMIT_OFILE ++#if !defined(__HAIKU__) && defined(RLIMIT_OFILE) + ADD_INT(module, RLIMIT_OFILE); + #endif + +-#ifdef RLIMIT_VMEM ++#if !defined(__HAIKU__) && defined(RLIMIT_VMEM) + ADD_INT(module, RLIMIT_VMEM); + #endif + +-#ifdef RLIMIT_AS ++#if !defined(__HAIKU__) && defined(RLIMIT_AS) + ADD_INT(module, RLIMIT_AS); + #endif + +-#ifdef RLIMIT_RSS ++#if !defined(__HAIKU__) && defined(RLIMIT_RSS) + ADD_INT(module, RLIMIT_RSS); + #endif + +-#ifdef RLIMIT_NPROC ++#if !defined(__HAIKU__) && defined(RLIMIT_NPROC) + ADD_INT(module, RLIMIT_NPROC); + #endif + +-#ifdef RLIMIT_MEMLOCK ++#if !defined(__HAIKU__) && defined(RLIMIT_MEMLOCK) + ADD_INT(module, RLIMIT_MEMLOCK); + #endif + +-#ifdef RLIMIT_SBSIZE ++#if !defined(__HAIKU__) && defined(RLIMIT_SBSIZE) + ADD_INT(module, RLIMIT_SBSIZE); + #endif + +diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h +index f5ca004..1ed1819 100644 +--- a/Modules/socketmodule.h ++++ b/Modules/socketmodule.h +@@ -111,6 +111,10 @@ typedef int socklen_t; + # undef AF_QIPCRTR + #endif + ++#if defined(__HAIKU__) ++#undef HAVE_BLUETOOTH_BLUETOOTH_H ++#endif ++ + #ifdef HAVE_BLUETOOTH_BLUETOOTH_H + #include + #include +diff --git a/Modules/spwdmodule.c b/Modules/spwdmodule.c +index 13f1115..45f477c 100644 +--- a/Modules/spwdmodule.c ++++ b/Modules/spwdmodule.c +@@ -9,6 +9,7 @@ + #ifdef HAVE_SHADOW_H + #include + #endif ++#include + + #include "clinic/spwdmodule.c.h" + +@@ -148,7 +149,12 @@ spwd_getspnam_impl(PyObject *module, PyObject *arg) + if (PyBytes_AsStringAndSize(bytes, &name, NULL) == -1) + goto out; + if ((p = getspnam(name)) == NULL) { ++// Haiku sets ENOENT if invalid user is specified. Ignore it to make KeyError is set. ++#ifdef __HAIKU__ ++ if (errno != 0 && errno != ENOENT) ++#else + if (errno != 0) ++#endif + PyErr_SetFromErrno(PyExc_OSError); + else + PyErr_SetString(PyExc_KeyError, "getspnam(): name not found"); +diff --git a/configure.ac b/configure.ac +index ba768ae..7d4c2a2 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1519,6 +1519,16 @@ if test $enable_shared = "yes"; then + PY3LIBRARY=libpython3.so + fi + ;; ++ Haiku*) ++ LDLIBRARY='libpython$(LDVERSION).so' ++ BLDLIBRARY='-L. -lpython$(LDVERSION)' ++ RUNSHARED=LIBRARY_PATH=`pwd`${LIBRARY_PATH:+:${LIBRARY_PATH}} ++ INSTSONAME="$LDLIBRARY".$SOVERSION ++ if test "$with_pydebug" != yes ++ then ++ PY3LIBRARY=libpython3.so ++ fi ++ ;; + hp*|HP*) + case `uname -m` in + ia64) +@@ -1664,6 +1674,7 @@ AC_PROG_MKDIR_P + AC_SUBST([LN]) + if test -z "$LN" ; then + case $ac_sys_system in ++ Haiku*) LN="ln -s";; + CYGWIN*) LN="ln -s";; + *) LN=ln;; + esac +@@ -3405,7 +3416,7 @@ then + else CCSHARED="+z"; + fi;; + Linux-android*) ;; +- Linux*|GNU*) CCSHARED="-fPIC";; ++ Linux*|GNU*|Haiku*) CCSHARED="-fPIC";; + Emscripten*|WASI*) + AS_VAR_IF([enable_wasm_dynamic_linking], [yes], [ + CCSHARED="-fPIC" +@@ -3438,7 +3449,7 @@ then + LINKFORSHARED="-Wl,-E -Wl,+s";; + # LINKFORSHARED="-Wl,-E -Wl,+s -Wl,+b\$(BINLIBDEST)/lib-dynload";; + Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; +- Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; ++ Linux*|GNU*|Haiku*) LINKFORSHARED="-Xlinker -export-dynamic";; + # -u libsys_s pulls in all symbols in libsys + Darwin/*) + LINKFORSHARED="$extra_undefs -framework CoreFoundation" +@@ -5585,6 +5596,7 @@ AC_CHECK_FUNC([__fpu_control], + AC_SUBST([LIBM]) + case $ac_sys_system in + Darwin) ;; ++Haiku) ;; + *) LIBM=-lm + esac + AC_MSG_CHECKING([for --with-libm=STRING]) +-- +2.42.0 + + +From 8060168bd8aad149b472d7df7eea26de9c762b6b Mon Sep 17 00:00:00 2001 +From: Jerome Duval +Date: Sun, 16 Apr 2017 10:05:42 +0200 +Subject: fix for negative errnos + + +diff --git a/Lib/subprocess.py b/Lib/subprocess.py +index 6df5dd5..39dde15 100644 +--- a/Lib/subprocess.py ++++ b/Lib/subprocess.py +@@ -1938,6 +1938,8 @@ class Popen: + SubprocessError) + if issubclass(child_exception_type, OSError) and hex_errno: + errno_num = int(hex_errno, 16) ++ if sys.platform.startswith('haiku'): ++ errno_num = -errno_num; + child_exec_never_called = (err_msg == "noexec") + if child_exec_never_called: + err_msg = "" +diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c +index 2d88f5e..4f4107d 100644 +--- a/Modules/_posixsubprocess.c ++++ b/Modules/_posixsubprocess.c +@@ -749,6 +749,10 @@ error: + char *cur; + _Py_write_noraise(errpipe_write, "OSError:", 8); + cur = hex_errno + sizeof(hex_errno); ++#ifdef __HAIKU__ ++ if (saved_errno < 0) ++ saved_errno = -saved_errno; ++#endif + while (saved_errno != 0 && cur != hex_errno) { + *--cur = Py_hexdigits[saved_errno % 16]; + saved_errno /= 16; +-- +2.42.0 + + +From 4612cb6c4e15103be299909cd0e70307e9040e2f Mon Sep 17 00:00:00 2001 +From: Oscar Lesta +Date: Sun, 8 Oct 2023 20:06:31 -0300 +Subject: Implement CTypes's find_library for Haiku + +This combines: + - the original patch by Philippe Houdoin + - A slight variation of Adrien Destugues' fix for x86_gcc2. + +diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py +index 0c2510e..6912890 100644 +--- a/Lib/ctypes/util.py ++++ b/Lib/ctypes/util.py +@@ -1,4 +1,5 @@ + import os ++import platform + import shutil + import subprocess + import sys +@@ -265,6 +266,60 @@ elif os.name == "posix": + def find_library(name, is64 = False): + return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name)) + ++ elif sys.platform.startswith("haiku"): ++ ++ def _num_version(libname): ++ # "libxyz.so.MAJOR.MINOR" => [ MAJOR, MINOR ] ++ parts = libname.split('.') ++ nums = [] ++ try: ++ while parts: ++ nums.insert(0, int(parts.pop())) ++ except ValueError: ++ pass ++ return nums or [sys.maxint] ++ ++ def find_library(name): ++ if name in ('c', 'm'): ++ return find_library('root') ++ for directory in os.environ['LIBRARY_PATH'].split(os.pathsep): ++ if directory.startswith("%A/"): ++ directory = directory.replace('%A', ++ os.path.dirname(os.path.abspath(sys.argv[0] or os.getcwd()))) ++ ++ # Are we on x86 32 bits?: ++ if platform.machine() == 'BePC': ++ directory = os.path.join(directory, "x86") ++ ++ if not os.path.isdir(directory): ++ continue ++ ++ # try direct match ++ fname = os.path.join(directory, name) ++ if os.path.isfile(fname): ++ return fname ++ ++ fname = os.path.join(directory, 'lib%s.so' % name) ++ if os.path.isfile(fname): ++ return fname ++ ++ # no exact matching in this directroy ++ # collect versioned candidates, if any ++ candidates = [] ++ pattern = re.compile(r'lib%s\.so\.\S+' % re.escape(name)) ++ for entry in os.listdir(directory): ++ if not os.path.isfile(os.path.join(directory, entry)): ++ continue ++ ++ if re.match(pattern, entry): ++ candidates.append(os.path.join(directory, entry)) ++ ++ if candidates: ++ # return latest version found ++ candidates.sort(key=_num_version) ++ return candidates[-1] ++ ++ return None + else: + + def _findSoname_ldconfig(name): +@@ -367,6 +422,12 @@ def test(): + print(f"crypt\t:: {cdll.LoadLibrary(find_library('crypt'))}") + print(f"crypto\t:: {find_library('crypto')}") + print(f"crypto\t:: {cdll.LoadLibrary(find_library('crypto'))}") ++ elif sys.platform.startswith("haiku"): ++ print(find_library("libbz2.so.1.0")) ++ print(find_library("tracker")) ++ print(find_library("media")) ++ print(cdll.LoadLibrary(find_library("tracker"))) ++ print(cdll.LoadLibrary("libmedia.so")) + else: + print(cdll.LoadLibrary("libm.so")) + print(cdll.LoadLibrary("libcrypt.so")) +-- +2.42.0 + + +From 8ee1d200626134a91f104725bb98855c5b233156 Mon Sep 17 00:00:00 2001 +From: Philipp Wolfer +Date: Mon, 23 Sep 2019 09:14:58 +0200 +Subject: webbrowser: Support for default browsers on Haiku + + +diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py +index e0170af..8567cdd 100755 +--- a/Lib/webbrowser.py ++++ b/Lib/webbrowser.py +@@ -477,6 +477,12 @@ def register_standard_browsers(): + # SerenityOS webbrowser, simply called "Browser". + register("Browser", None, BackgroundBrowser("Browser")) + ++ if sys.platform[:5] == "haiku": ++ # First try to use the default configured browser ++ register("haiku-default", None, GenericBrowser("open")) ++ # Fall back to WebPositive as the standard browser of Haiku ++ register("webpositive", None, BackgroundBrowser("WebPositive")) ++ + if sys.platform[:3] == "win": + # First try to use the default Windows browser + register("windows-default", WindowsDefault) +-- +2.42.0 + + +From 14eb288ddca79c42e4d8ab2edaba990a04e3dc7e Mon Sep 17 00:00:00 2001 +From: Jerome Duval +Date: Fri, 4 Oct 2019 22:02:35 +0200 +Subject: since 3.8, don't reinit locks on fork. + + +diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py +index 056380f..4836719 100644 +--- a/Lib/logging/__init__.py ++++ b/Lib/logging/__init__.py +@@ -250,7 +250,7 @@ def _releaseLock(): + + # Prevent a held logging lock from blocking a child from logging. + +-if not hasattr(os, 'register_at_fork'): # Windows and friends. ++if sys.platform.startswith('haiku') or not hasattr(os, 'register_at_fork'): # Windows and friends. + def _register_at_fork_reinit_lock(instance): + pass # no-op when os.register_at_fork does not exist. + else: +-- +2.42.0 + + +From 607f0a89afcf78f21a9341a861ff392bf86c9dd4 Mon Sep 17 00:00:00 2001 +From: Jerome Duval +Date: Fri, 15 May 2020 15:20:57 +0200 +Subject: handle errors returned by internal_connect() + +upstream bug #40628 by Ryan C. Gordon + +diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c +index 4ec68e2..ce5940a 100644 +--- a/Modules/socketmodule.c ++++ b/Modules/socketmodule.c +@@ -3489,7 +3489,7 @@ sock_connect(PySocketSockObject *s, PyObject *addro) + } + + res = internal_connect(s, SAS2SA(&addrbuf), addrlen, 1); +- if (res < 0) ++ if (res == -1) + return NULL; + + Py_RETURN_NONE; +@@ -3520,7 +3520,7 @@ sock_connect_ex(PySocketSockObject *s, PyObject *addro) + } + + res = internal_connect(s, SAS2SA(&addrbuf), addrlen, 0); +- if (res < 0) ++ if (res == -1) + return NULL; + + return PyLong_FromLong((long) res); +-- +2.42.0 + + +From 959d4fd2ff3ebe73727ad275c2a48018bab26f11 Mon Sep 17 00:00:00 2001 +From: Jerome Duval +Date: Mon, 19 Oct 2020 18:03:09 +0200 +Subject: ttyname_r can use MAXPATHLEN + + +diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c +index b9ca286..8badc69 100644 +--- a/Modules/posixmodule.c ++++ b/Modules/posixmodule.c +@@ -3150,11 +3150,14 @@ static PyObject * + os_ttyname_impl(PyObject *module, int fd) + /*[clinic end generated code: output=c424d2e9d1cd636a input=9ff5a58b08115c55]*/ + { +- ++#ifndef __HAIKU__ + long size = sysconf(_SC_TTY_NAME_MAX); + if (size == -1) { + return posix_error(); + } ++#else ++ long size = MAXPATHLEN; ++#endif + char *buffer = (char *)PyMem_RawMalloc(size); + if (buffer == NULL) { + return PyErr_NoMemory(); +-- +2.42.0 + + +From 2b11dd68750848d57c2d29e9d03905664989f826 Mon Sep 17 00:00:00 2001 +From: Oscar Lesta +Date: Mon, 24 Oct 2022 20:04:10 -0300 +Subject: Lib/test: require the "largefile" usage flag for I/O heavy tests. + +The same is done for Windows and macOS already. + +This avoids needing several GBs of storage to run the tests +(unless the "largefile" resource usage flag is enabled). + +diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py +index e032325..ffff694 100644 +--- a/Lib/test/test_io.py ++++ b/Lib/test/test_io.py +@@ -609,7 +609,7 @@ class IOTest(unittest.TestCase): + # On Windows and Mac OSX this test consumes large resources; It takes + # a long time to build the >2 GiB file and takes >2 GiB of disk space + # therefore the resource must be enabled to run this test. +- if sys.platform[:3] == 'win' or sys.platform == 'darwin': ++ if sys.platform[:3] == 'win' or sys.platform == 'darwin' or sys.platform[:5] == 'haiku': + support.requires( + 'largefile', + 'test requires %s bytes and a long time to run' % self.LARGE) +diff --git a/Lib/test/test_largefile.py b/Lib/test/test_largefile.py +index 3b0930f..c793ea1 100644 +--- a/Lib/test/test_largefile.py ++++ b/Lib/test/test_largefile.py +@@ -255,7 +255,7 @@ def setUpModule(): + # takes a long time to build the >2 GiB file and takes >2 GiB of disk + # space therefore the resource must be enabled to run this test. + # If not, nothing after this line stanza will be executed. +- if sys.platform[:3] == 'win' or sys.platform == 'darwin': ++ if sys.platform[:3] == 'win' or sys.platform == 'darwin' or sys.platform[:5] == 'haiku': + requires('largefile', + 'test requires %s bytes and a long time to run' % str(size)) + else: +diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py +index dfcf303..886d3af 100644 +--- a/Lib/test/test_mmap.py ++++ b/Lib/test/test_mmap.py +@@ -1007,7 +1007,7 @@ class LargeMmapTests(unittest.TestCase): + unlink(TESTFN) + + def _make_test_file(self, num_zeroes, tail): +- if sys.platform[:3] == 'win' or sys.platform == 'darwin': ++ if sys.platform[:3] == 'win' or sys.platform == 'darwin' or sys.platform[:5] == 'haiku': + requires('largefile', + 'test requires %s bytes and a long time to run' % str(0x180000000)) + f = open(TESTFN, 'w+b') +-- +2.42.0 + + +From e2bd114cfa56d90620bccd2985e87c51ee8d34cb Mon Sep 17 00:00:00 2001 +From: Oscar Lesta +Date: Sun, 8 Oct 2023 01:04:42 -0300 +Subject: default schemes for Haiku + +Based on previous patches by Jerome Duval. + +diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py +index 122d441..a27fa57 100644 +--- a/Lib/sysconfig.py ++++ b/Lib/sysconfig.py +@@ -47,6 +47,34 @@ _INSTALL_SCHEMES = { + 'scripts': '{base}/bin', + 'data': '{base}', + }, ++ 'haiku': { ++ 'stdlib': '{installed_base}/{platlibdir}/python{py_version_short}', ++ 'platstdlib': '{platbase}/{platlibdir}/python{py_version_short}', ++ 'purelib': '{base}/non-packaged/lib/python{py_version_short}/site-packages', ++ 'platlib': '{platbase}/non-packaged/{platlibdir}/python{py_version_short}/site-packages', ++ 'include': '{base}/non-packaged/develop/headers/python{py_version_short}', ++ 'scripts': '{base}/non-packaged/bin', ++ 'data' : '{base}/non-packaged', ++ }, ++ 'haiku_vendor': { ++ 'stdlib': '{installed_base}/{platlibdir}/python{py_version_short}', ++ 'platstdlib': '{platbase}/{platlibdir}/python{py_version_short}', ++ 'purelib': '{base}/lib/python{py_version_short}/vendor-packages', ++ 'platlib': '{platbase}/lib/python{py_version_short}/vendor-packages', ++ 'include': '{base}/develop/headers/python{py_version_short}', ++ 'scripts': '{base}/bin', ++ 'data' : '{base}', ++ }, ++ 'haiku_home': { ++ 'stdlib': '{installed_base}/lib/python', ++ 'platstdlib': '{base}/lib/python', ++ 'purelib': '{base}/lib/python', ++ 'platlib': '{base}/lib/python', ++ 'include': '{installed_base}/develop/headers/python', ++ 'platinclude': '{installed_base}/develop/headers/python', ++ 'scripts': '{base}/bin', ++ 'data': '{base}', ++ }, + 'nt': { + 'stdlib': '{installed_base}/Lib', + 'platstdlib': '{base}/Lib', +@@ -152,6 +180,15 @@ if _HAS_USER_BASE: + 'scripts': '{userbase}/bin', + 'data': '{userbase}', + }, ++ 'haiku_user': { ++ 'stdlib': '{userbase}/{platlibdir}/python{py_version_short}', ++ 'platstdlib': '{userbase}/{platlibdir}/python{py_version_short}', ++ 'purelib': '{userbase}/lib/python{py_version_short}/site-packages', ++ 'platlib': '{userbase}/lib/python{py_version_short}/site-packages', ++ 'include': '{userbase}/develop/headers/python{py_version_short}', ++ 'scripts': '{userbase}/bin', ++ 'data': '{userbase}', ++ }, + 'osx_framework_user': { + 'stdlib': '{userbase}/lib/python', + 'platstdlib': '{userbase}/lib/python', +@@ -282,6 +319,18 @@ def _expand_vars(scheme, vars): + + + def _get_preferred_schemes(): ++ if sys.platform.startswith('haiku'): ++ if os.environ.get('HAIKU_USE_VENDOR_DIRECTORIES') == '1': ++ return { ++ 'prefix': 'haiku_vendor', ++ 'home': 'haiku_home', ++ 'user': 'haiku_user', ++ } ++ return { ++ 'prefix': 'haiku', ++ 'home': 'haiku_home', ++ 'user': 'haiku_user', ++ } + if os.name == 'nt': + return { + 'prefix': 'nt', +-- +2.42.0 + + +From 3e16846d599f86dc1060af64ee270aaf450d628a Mon Sep 17 00:00:00 2001 +From: Oscar Lesta +Date: Sun, 8 Oct 2023 01:05:12 -0300 +Subject: Fix _getuserbase() and getsizepackages() for Haiku. + +Based on previous patches by Jerome Duval and me. + +diff --git a/Lib/site.py b/Lib/site.py +index 672fa7b..e783664 100644 +--- a/Lib/site.py ++++ b/Lib/site.py +@@ -281,6 +281,14 @@ def _getuserbase(): + return joinuser("~", "Library", sys._framework, + "%d.%d" % sys.version_info[:2]) + ++ if sys.platform.startswith('haiku'): ++ try: ++ import subprocess ++ return subprocess.run(['finddir', 'B_USER_NONPACKAGED_DIRECTORY'], ++ stdout=subprocess.PIPE, check=True).stdout.rstrip().decode('utf-8') ++ except: ++ pass ++ + return joinuser("~", ".local") + + +@@ -361,7 +369,14 @@ def getsitepackages(prefixes=None): + continue + seen.add(prefix) + +- if os.sep == '/': ++ if sys.platform.startswith('haiku'): ++ sitepackages.append(os.path.join(prefix, "non-packaged", "lib", ++ "python%d.%d" % sys.version_info[:2], ++ "site-packages")) ++ sitepackages.append(os.path.join(prefix, "lib", ++ "python%d.%d" % sys.version_info[:2], ++ "vendor-packages")) ++ elif os.sep == '/': + libdirs = [sys.platlibdir] + if sys.platlibdir != "lib": + libdirs.append("lib") +diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py +index a27fa57..80e1c3f 100644 +--- a/Lib/sysconfig.py ++++ b/Lib/sysconfig.py +@@ -155,6 +155,14 @@ def _getuserbase(): + return joinuser("~", "Library", sys._framework, + f"{sys.version_info[0]}.{sys.version_info[1]}") + ++ if sys.platform.startswith('haiku'): ++ try: ++ import subprocess ++ return subprocess.run(['finddir', 'B_USER_NONPACKAGED_DIRECTORY'], ++ stdout=subprocess.PIPE, check=True).stdout.rstrip().decode('utf-8') ++ except: ++ pass ++ + return joinuser("~", ".local") + + _HAS_USER_BASE = (_getuserbase() is not None) +-- +2.42.0 + + +From 374f9308fed872a638ea31a041ff2e476bc95220 Mon Sep 17 00:00:00 2001 +From: Oscar Lesta +Date: Sun, 8 Oct 2023 01:05:31 -0300 +Subject: Fix location of REPL's history file. + +From "initial Haiku patch" by Jerome Duval. + +diff --git a/Lib/site.py b/Lib/site.py +index e783664..da965d6 100644 +--- a/Lib/site.py ++++ b/Lib/site.py +@@ -480,8 +480,16 @@ def enablerlcompleter(): + # each interpreter exit when readline was already configured + # through a PYTHONSTARTUP hook, see: + # http://bugs.python.org/issue5845#msg198636 +- history = os.path.join(os.path.expanduser('~'), +- '.python_history') ++ import subprocess ++ try: ++ history = os.path.join(subprocess.run(['finddir', 'B_USER_VAR_DIRECTORY'], ++ check=True, stdout=subprocess.PIPE).stdout.rstrip().decode('utf-8'), ++ 'python', 'history') ++ if not os.path.exists(os.path.dirname(history)): ++ os.makedirs(os.path.dirname(history)) ++ except subprocess.CalledProcessError: ++ history = os.path.join(os.path.expanduser('~'), ++ '.python_history') + try: + readline.read_history_file(history) + except OSError: +-- +2.42.0 + + +From a4920c9e12d2225ec24df04ef1686a6ad63adb31 Mon Sep 17 00:00:00 2001 +From: Oscar Lesta +Date: Sun, 8 Oct 2023 02:17:22 -0300 +Subject: Miscellaneous "Lib/test/" fixes for Haiku. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +test_fileio.py fix from "initial Haiku patch" by Jérôme Duval. + +diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py +index 55e0619..24a811e 100644 +--- a/Lib/test/datetimetester.py ++++ b/Lib/test/datetimetester.py +@@ -5917,6 +5917,9 @@ def pairs(iterable): + + class ZoneInfo(tzinfo): + zoneroot = '/usr/share/zoneinfo' ++ if sys.platform.startswith('haiku'): ++ zoneroot = '/system/data/zoneinfo' ++ + def __init__(self, ut, ti): + """ + +diff --git a/Lib/test/test_email/test_utils.py b/Lib/test/test_email/test_utils.py +index 25fa48c..ee46514 100644 +--- a/Lib/test/test_email/test_utils.py ++++ b/Lib/test/test_email/test_utils.py +@@ -145,7 +145,8 @@ class LocaltimeTests(unittest.TestCase): + # XXX: Need a more robust test for Olson's tzdata + @unittest.skipIf(sys.platform.startswith('win'), + "Windows does not use Olson's TZ database") +- @unittest.skipUnless(os.path.exists('/usr/share/zoneinfo') or ++ @unittest.skipUnless(os.path.exists('/system/data/zoneinfo') or ++ os.path.exists('/usr/share/zoneinfo') or + os.path.exists('/usr/lib/zoneinfo'), + "Can't find the Olson's TZ database") + @test.support.run_with_tz('Europe/Kiev') +diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py +index ebfcffd..0517b87 100644 +--- a/Lib/test/test_fileio.py ++++ b/Lib/test/test_fileio.py +@@ -391,6 +391,7 @@ class OtherFileTests: + self.assertEqual(f.writable(), True) + if sys.platform != "darwin" and \ + 'bsd' not in sys.platform and \ ++ 'haiku' not in sys.platform and \ + not sys.platform.startswith(('sunos', 'aix')): + # Somehow /dev/tty appears seekable on some BSDs + self.assertEqual(f.seekable(), False) +-- +2.42.0 + + +From b12c15d58f31c69459b41bf652e9f271e0a1604f Mon Sep 17 00:00:00 2001 +From: Oscar Lesta +Date: Sun, 8 Oct 2023 17:02:19 -0300 +Subject: Use spawn instead of fork for multiprocessing. + +Without this change, we get: + +``` +Fatal Python error: PyOS_AfterFork_Child: + the function must be called with the GIL held, after Python initialization + and before Python finalization, but the GIL is released (the current Python + thread state is NULL) +``` + +when running "test_re.py" (as part of the "--with-optimizations" build) without +using spawn instead of fork in multiprocessing/context.py. + +and also: + +``` +Traceback (most recent call last): + File "", line 1, in + File "/sources/Python-3.12.0/Lib/multiprocessing/forkserver.py", line 202, in main + signal.set_wakeup_fd(sig_w) +ValueError: the fd 6 must be in non-blocking mode +``` + +when running the "compileall" step of "make install". + +From: +https://docs.python.org/3.12/library/multiprocessing.html#contexts-and-start-methods + +"The default start method will change away from fork in Python 3.14." + +So, we might be in the clear switching to "spawn" now. + +diff --git a/Lib/multiprocessing/context.py b/Lib/multiprocessing/context.py +index de8a264..02a301e 100644 +--- a/Lib/multiprocessing/context.py ++++ b/Lib/multiprocessing/context.py +@@ -320,7 +320,7 @@ if sys.platform != 'win32': + 'spawn': SpawnContext(), + 'forkserver': ForkServerContext(), + } +- if sys.platform == 'darwin': ++ if sys.platform == 'darwin' or sys.platform[:5] == 'haiku': + # bpo-33725: running arbitrary code after fork() is no longer reliable + # on macOS since macOS 10.14 (Mojave). Use spawn by default instead. + _default_context = DefaultContext(_concrete_contexts['spawn']) +-- +2.42.0 + diff --git a/dev-lang/python/python3.12-3.12.0.recipe b/dev-lang/python/python3.12-3.12.0.recipe new file mode 100644 index 000000000..14491dd9b --- /dev/null +++ b/dev-lang/python/python3.12-3.12.0.recipe @@ -0,0 +1,320 @@ +SUMMARY="An interpreted, interactive, object-oriented programming language" +DESCRIPTION="Python is a programming language that lets you work more quickly \ +and integrate your systems more effectively. You can learn to use Python and \ +see almost immediate gains in productivity and lower maintenance costs. + +Python runs on Windows, Linux/Unix, Mac OS X, and has been ported to the Java \ +and .NET virtual machines. + +Python is free to use, even for commercial products, because of its \ +OSI-approved open source license." +HOMEPAGE="https://www.python.org" +LICENSE="Python" +COPYRIGHT="1990-2023 Python Software Foundation" +REVISION="1" +SOURCE_URI="https://www.python.org/ftp/python/$portVersion/Python-${portVersion}.tar.xz" +CHECKSUM_SHA256="795c34f44df45a0e9b9710c8c71c15c671871524cd412ca14def212e8ccb155d" +SOURCE_DIR="Python-${portVersion}" + +pyShortVer="${portVersion%.*}" +pyVersionCompat="$portVersion compat >= $pyShortVer" + +PATCHES="python$pyShortVer-$portVersion.patchset" + +ARCHITECTURES="all !x86_gcc2" +SECONDARY_ARCHITECTURES="x86" + +# On x86_gcc2 we don't want to install the commands in bin//, but in bin/. +commandSuffix=$secondaryArchSuffix +commandBinDir=$binDir +if [ "$targetArchitecture" = x86_gcc2 ]; then + commandSuffix= + commandBinDir=$prefix/bin +fi + +GLOBAL_WRITABLE_FILES=" + non-packaged/lib/python$pyShortVer/site-packages directory keep-old + " + +PROVIDES=" + python$pyShortVer$secondaryArchSuffix = $pyVersionCompat + cmd:2to3_$pyShortVer = $pyVersionCompat + cmd:idle$pyShortVer = $pyVersionCompat + cmd:pydoc$pyShortVer = $pyVersionCompat + cmd:python$pyShortVer = $pyVersionCompat + cmd:python${pyShortVer}_config = $pyVersionCompat + cmd:pyvenv_$pyShortVer = $pyVersionCompat + devel:libpython$pyShortVer$secondaryArchSuffix = 1.0 + lib:libpython$pyShortVer$secondaryArchSuffix = 1.0 + " +REQUIRES=" + haiku$secondaryArchSuffix + timezone_data + cmd:file + lib:libbz2$secondaryArchSuffix + lib:libedit$secondaryArchSuffix + lib:libexpat$secondaryArchSuffix + lib:libffi$secondaryArchSuffix + lib:libintl$secondaryArchSuffix + lib:liblzma$secondaryArchSuffix + lib:libncurses$secondaryArchSuffix + lib:libsqlite3$secondaryArchSuffix + lib:libssl$secondaryArchSuffix + lib:libz$secondaryArchSuffix + " +BUILD_REQUIRES=" + haiku${secondaryArchSuffix}_devel + devel:libbz2$secondaryArchSuffix + devel:libedit$secondaryArchSuffix + devel:libexpat$secondaryArchSuffix + devel:libffi$secondaryArchSuffix + devel:liblzma$secondaryArchSuffix + devel:libncurses$secondaryArchSuffix + devel:libsqlite3$secondaryArchSuffix + devel:libssl$secondaryArchSuffix + devel:libtclstub8.6$secondaryArchSuffix + devel:libtk8.6$secondaryArchSuffix + devel:libz$secondaryArchSuffix + " +BUILD_PREREQUIRES=" + autoconf_archive + cmd:aclocal + cmd:autoconf + cmd:find + cmd:gcc$secondaryArchSuffix + cmd:ld$secondaryArchSuffix + cmd:libtoolize$secondaryArchSuffix + cmd:make + cmd:pkg_config$secondaryArchSuffix + cmd:python3 >= 3.10 # because using `export PYTHON_FOR_REGEN="./python"` is just unreliable. + " + +# For some reason, test_zoneinfo fails to find it when running the tests inside the chroot, +# but works when calling the test with an installed Python 3.12. +TEST_REQUIRES=" + timezone_data + " + +# If set to "yes", the resulting "_tests" package is around 30 MB in size. +packageTests="no" +if [ "$packageTests" = "yes" ]; then + PROVIDES_tests=" + python$pyShortVer${secondaryArchSuffix}_tests = $portVersion + " + REQUIRES_tests=" + python$pyShortVer$secondaryArchSuffix == $portVersion base + " +fi + +BUILD() +{ + autoreconf -fi + + # From ./configure: + # "compiler flags are generated in two sets, BASECFLAGS and OPT. OPT is just + # for debug/optimization stuff. BASECFLAGS is for flags that are required + # just to get things to compile and link." + export BASECFLAGS="-D_BSD_SOURCE" + + # Not exporting OPT ends up with "-g -fwrapv -O3 -Wall" being used, + # and using OPT="" means the build ends up being "-O0". + export OPT="-fwrapv -O3 -Wall" + + # Unless cmd:python3 >= 3.10 is available (by being listed on BUILD_PREREQUIRES), we'll + # get "python3: command not found" when the build tries to generate some files. + # We can force the use of the "./python" built on the chroot instead: + # export PYTHON_FOR_REGEN="./python" + + # But using that ocassionally fails with: + # "runtime_loader: Cannot open file libpython3.12.so.1.0 (needed by /sources/Python-3.12.0/python): No such file or directory" + # Perhaps this alternative might work?: + # export PYTHON_FOR_REGEN="LD_PRELOAD=./libpython3.12.so.1.0 ./python" + + runConfigure --omit-dirs binDir,includeDir ./configure \ + --bindir=$commandBinDir \ + --includedir=$developDir/headers \ + --enable-optimizations \ + --enable-shared \ + --with-ensurepip=no \ + --with-readline=editline \ + --with-system-expat \ + --with-tzpath=$dataDir/zoneinfo \ + --without-static-libpython + # --with-lto # this one is too CPU/RAM intensive. + + # Uncomment when doing repeated builds (for testing different flags/options). + # make clean && rm -f python + + # NOTE: When using "--enable-optimizations" above, using "make $jobArgs" might be unreliable. + # Can see several instances of, for example: + # + # libgcov profiling error:/sources/Python-3.xx.x/Objects/unicodeobject.gcda:Merge mismatch for function 477 + # libgcov profiling error:/sources/Python-3.xx.x/Objects/obmalloc.gcda:Merge mismatch for function 23 + # + # Build might end OK (with only some "missing profile" warnings later on), or it can fail + # with something like: + # + # "Parser/parser.c:38718:1: error: corrupted profile info: invalid time profile" + # + # Not using multiple jobs for make solves both the warnings and the possible error. + # make $jobArgs + make -j 1 +} + +INSTALL() +{ + # altinstall avoids clobbering $prefix/bin/{2to3,idle3,pydoc3,python3,python3-config} + make altinstall + + # Remove this one for "make altinstall" Python versions on Haiku. + rm $libDir/libpython3.so + + if [ "$targetArchitecture" = x86_gcc2 ]; then + # On x86_gcc2, move lib-dynload to lib/python3.x/ + mv $libDir/python$pyShortVer/lib-dynload $prefix/lib/python$pyShortVer/ + fi + prepareInstalledDevelLibs libpython$pyShortVer + fixPkgconfig + if [ "$targetArchitecture" = x86_gcc2 ]; then + # fix pkgconfig to match configure flags + sed -i -e 's,headers/x86,headers,' $developLibDir/pkgconfig/python*.pc + fi + + mkdir -p $prefix/lib/python$pyShortVer/vendor-packages + echo 'This directory contains packaged python modules.' \ + >$prefix/lib/python$pyShortVer/vendor-packages/README + + mkdir -p $prefix/non-packaged/lib/python$pyShortVer + mv $prefix/lib/python$pyShortVer/site-packages $prefix/non-packaged/lib/python$pyShortVer/ + + if [ "$packageTests" = "yes" ]; then + packageEntries tests \ + $prefix/lib/python$pyShortVer/idlelib/idle_test \ + $prefix/lib/python$pyShortVer/test + else + # drop testsuite altogether + cd $prefix/lib/python$pyShortVer + rm -rf idlelib/idle_test test + fi +} + +# Some of the test will crash, invoking the crash dialog, and will hang waiting for +# user's interaction. To avoid that, make sure to configure your system by adding +# the following lines in the file "~/config/settings/system/debug_server/settings": +##--- +# executable_actions { +# /sources/Python-3.*/python kill +# } +##--- + +# For some tests that purposefully crash, it would make sense to add support for +# crash-report suppression (as done for other platforms) on "tests/support/__init__,py"'s +# SuppressCrashReport class. +# But that needs support from Haiku's debug_server, as we can't change settings from +# the recipe's building environment at the moment (https://dev.haiku-os.org/ticket/10301) + +# To see the available test-runs options: +# > hp -E python3.12 +# > LIBRARY_PATH=/sources/Python-3.12.0:%A/lib:/boot/home/config/non-packaged/lib:/boot/home/config/lib:/boot/system/non-packaged/lib:/boot/system/lib python -m test --help +# or just: +# > LD_PRELOAD=./libpython3.12.so.1.0 python -m test --help +# +# To only execute a particular test (from the $sourceDir): +# +# > LD_PRELOAD=./libpython3.12.so.1.0 python -m test test_datetime -W + +TEST() +{ + # Remove tests data left-overs, if any: + # rm -f -r /boot/system/cache/tmp/ + # rm -f -d -r build/test_python* + make $jobArgs test EXTRATESTOPTS="--cleanup" + + local test_options=( + # Use this to get same test order on different runs (actual value not important). + --randseed 7858065 + + # Print the names of the 10 slowest tests. + --slowest + + # Possibly useful? + # --tempdir=/another_drive/tmp + + # Enable/disable certain tests by "resource" type: + # -uall,-audio,-cpu,-curses,-decimal,-gui,-largefile,-network,-subprocess,-urlfetch + + # The following tests invoke the crash dialog, and unless your configure + # debug_server default action to "kill" or "report", they will hang waiting for + # user input. See comment above TEST(). + -x test_faulthandler + -x test_futures # from test_asyncio. Crashes: Exception (Segment violation) + -x test_subprocess # tends to hang. + -x test_threading # tends to hang. + + # Many of the tests hang/stall. We have two options: + # + # 1- Manually remove the problematic test-cases. + # 2- Set a TIMEOUT (ej: --timeout=300) + # + # Option 1: Works, but requires manual identification/mainteinance. + # Option 2: Doesn't requires maintaining a list of stalling tests, but: + # at the end of the test run it causes: + # "unmounting failed: Device/File/Resource Busy" errors, as there are + # dangling threads running when the tests timeout (requiring "killall python") + # + # Let's use Option 1. + + # These hang reliably. + -x test__xxsubinterpreters + -x test_cmd_line + -x test_concurrent_futures + -x test_eintr + -x test_interpreters + -x test_multiprocessing_fork + -x test_multiprocessing_forkserver + -x test_multiprocessing_main_handling + -x test_multiprocessing_spawn + -x test_os + -x test_posix + -x test_random + -x test_socketserver + -x test_threaded_import # test_importlib/test_threaded_import + -x test_tracemalloc + -x test_uuid + + # "test_asyncio" doesn't seems to runs reliably, even after individually skipping + # all the problematic test-cases that could be identify by running them one by one. + # -x test_asyncio + # The following are all under test_asyncio/ + -x test_base_events + -x test_buffered_proto # Exception on Exception handler. + -x test_events + -x test_sendfile + -x test_server # Exception on Exception handler. + -x test_sock_lowlevel + -x test_sslproto # Exception on Exception handler. + -x test_streams + -x test_unix_events + # -i TestThreadedServer # in test_asyncio.functioonal + + # These not always hang/stall, but they do it enough to warrant skipping for now. + -x test_imaplib + -x test_signal + -x test_socket + -x test_ssl + -x test_urllib2_localnet + + # 3.11 + -x test_urllib2net + -x test_venv + + # 3.12 Either too slow or hangs; + -x test_builtin + -x test_mailbox + -x test_tempfile + -x test_thread + ) + + local -x LOGNAME=buildbot # this skips tests_tools/test_freeze, copied from Gentoo's ebuild + make $jobArgs test EXTRATESTOPTS="${test_options[*]}" +}