diff --git a/Makefile b/Makefile
index 03c4ff3e52..1b31d26bfb 100644
--- a/Makefile
+++ b/Makefile
@@ -60,19 +60,6 @@ testapps-with-numpy/%: virtualenv
--arch=armeabi-v7a --arch=arm64-v8a --arch=x86_64 --arch=x86 \
--permission "(name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)" --permission "(name=android.permission.INTERNET)"
-testapps-with-scipy: testapps-with-scipy/debug/apk testapps-with-scipy/release/aab
-
-# testapps-with-scipy/MODE/ARTIFACT
-testapps-with-scipy/%: virtualenv
- $(eval MODE := $(word 2, $(subst /, ,$@)))
- $(eval ARTIFACT := $(word 3, $(subst /, ,$@)))
- @echo Building testapps-with-scipy for $(MODE) mode and $(ARTIFACT) artifact
- . $(ACTIVATE) && cd testapps/on_device_unit_tests/ && \
- export LEGACY_NDK=$(ANDROID_NDK_HOME_LEGACY) && \
- python setup.py $(ARTIFACT) --$(MODE) --sdk-dir $(ANDROID_SDK_HOME) --ndk-dir $(ANDROID_NDK_HOME) \
- --requirements python3,scipy,kivy \
- --arch=armeabi-v7a --arch=arm64-v8a
-
testapps-webview: testapps-webview/debug/apk testapps-webview/release/aab
# testapps-webview/MODE/ARTIFACT
diff --git a/ci/constants.py b/ci/constants.py
index 382a4a0bfe..458d4bd704 100644
--- a/ci/constants.py
+++ b/ci/constants.py
@@ -25,8 +25,6 @@ class TargetPython(Enum):
# mpmath package with a version >= 0.19 required
'sympy',
'vlc',
- # need extra gfortran NDK system add-on
- 'lapack', 'scipy',
# Outdated and there's a chance that is now useless.
'zope_interface',
# Requires zope_interface, which is broken.
diff --git a/ci/makefiles/android.mk b/ci/makefiles/android.mk
index 2041a6ce76..b9aecffc14 100644
--- a/ci/makefiles/android.mk
+++ b/ci/makefiles/android.mk
@@ -1,7 +1,7 @@
# Downloads and installs the Android SDK depending on supplied platform: darwin or linux
# Those android NDK/SDK variables can be override when running the file
-ANDROID_NDK_VERSION ?= 25b
+ANDROID_NDK_VERSION ?= 27c
ANDROID_NDK_VERSION_LEGACY ?= 21e
ANDROID_SDK_TOOLS_VERSION ?= 6514223
ANDROID_SDK_BUILD_TOOLS_VERSION ?= 29.0.3
diff --git a/doc/source/quickstart.rst b/doc/source/quickstart.rst
index 61c33d6f16..449f1314c0 100644
--- a/doc/source/quickstart.rst
+++ b/doc/source/quickstart.rst
@@ -119,7 +119,7 @@ named ``tools``, and you will need to run extra commands to install
the SDK packages needed.
For Android NDK, note that modern releases will only work on a 64-bit
-operating system. **The minimal, and recommended, NDK version to use is r25b:**
+operating system. **The minimal, and recommended, NDK version to use is r27c:**
- `Go to ndk downloads page `_
- Windows users should create a virtual machine with an GNU Linux os
diff --git a/pythonforandroid/recipe.py b/pythonforandroid/recipe.py
index 44469aef2c..e277bcb817 100644
--- a/pythonforandroid/recipe.py
+++ b/pythonforandroid/recipe.py
@@ -76,7 +76,7 @@ class Recipe(metaclass=RecipeMeta):
_version = None
'''A string giving the version of the software the recipe describes,
- e.g. ``2.0.3`` or ``master``.'''
+ e.g. ``2.0.3``. In case of git repository version is branch or a tagged release e.g. ``v12.3`` or ``develop``.'''
md5sum = None
'''The md5sum of the source from the :attr:`url`. Non-essential, but
@@ -155,6 +155,11 @@ class Recipe(metaclass=RecipeMeta):
starting from NDK r18 the `gnustl_shared` lib has been deprecated.
'''
+ min_ndk_api_support = 20
+ '''
+ Minimum ndk api your recipe will support
+ '''
+
def get_stl_library(self, arch):
return join(
arch.ndk_lib_dir,
@@ -252,23 +257,20 @@ def report_hook(index, blksize, size):
if not isdir(target):
if url.startswith('git+'):
url = url[4:]
- # if 'version' is specified, do a shallow clone
- if self.version:
- ensure_dir(target)
- with current_directory(target):
- shprint(sh.git, 'init')
- shprint(sh.git, 'remote', 'add', 'origin', url)
- else:
- shprint(sh.git, 'clone', '--recursive', url, target)
- with current_directory(target):
- if self.version:
- shprint(sh.git, 'fetch', '--tags', '--depth', '1')
- shprint(sh.git, 'checkout', self.version)
- branch = sh.git('branch', '--show-current')
- if branch:
- shprint(sh.git, 'pull')
- shprint(sh.git, 'pull', '--recurse-submodules')
- shprint(sh.git, 'submodule', 'update', '--recursive', '--init', '--depth', '1')
+
+ shprint(
+ sh.git,
+ 'clone',
+ '--branch',
+ self.version,
+ '--depth',
+ '1',
+ '--recurse-submodules',
+ '--shallow-submodules',
+ url,
+ target,
+ )
+
return target
def apply_patch(self, filename, arch, build_dir=None):
@@ -375,7 +377,12 @@ def get_recipe_dir(self):
# Public Recipe API to be subclassed if needed
def download_if_necessary(self):
+ if self.ctx.ndk_api < self.min_ndk_api_support:
+ error(f"In order to build '{self.name}', you must set minimum ndk api (minapi) to `{self.min_ndk_api_support}`.\n")
+ exit(1)
+
info_main('Downloading {}'.format(self.name))
+
user_dir = environ.get('P4A_{}_DIR'.format(self.name.lower()))
if user_dir is not None:
info('P4A_{}_DIR is set, skipping download for {}'.format(
@@ -919,6 +926,32 @@ def folder_name(self):
name = self.name
return name
+ def patch_shebang(self, _file, original_bin):
+ _file_des = open(_file, "r")
+
+ try:
+ data = _file_des.readlines()
+ except UnicodeDecodeError:
+ return
+
+ if "#!" in (line := data[0]):
+ if line.split("#!")[-1].strip() == original_bin:
+ return
+
+ info(f"Fixing sheband for '{_file}'")
+ data.pop(0)
+ data.insert(0, "#!" + original_bin + "\n")
+ _file_des.close()
+ _file_des = open(_file, "w")
+ _file_des.write("".join(data))
+ _file_des.close()
+
+ def patch_shebangs(self, path, original_bin):
+ # set correct shebang
+ for file in listdir(path):
+ _file = join(path, file)
+ self.patch_shebang(_file, original_bin)
+
def get_recipe_env(self, arch=None, with_flags_in_cc=True):
env = super().get_recipe_env(arch, with_flags_in_cc)
env['PYTHONNOUSERSITE'] = '1'
@@ -1260,6 +1293,9 @@ def build_arch(self, arch):
self.install_hostpython_prerequisites(
packages=["build[virtualenv]", "pip"] + self.hostpython_prerequisites
)
+ python_bin_dir = join(self.hostpython_site_dir, "bin")
+ self.patch_shebangs(python_bin_dir, self.real_hostpython_location)
+
build_dir = self.get_build_dir(arch.arch)
env = self.get_recipe_env(arch, with_flags_in_cc=True)
# make build dir separately
@@ -1308,6 +1344,7 @@ def get_recipe_meson_options(self, arch):
"cpp_args": self.sanitize_flags(env["CXXFLAGS"], env["CPPFLAGS"]),
"c_link_args": self.sanitize_flags(env["LDFLAGS"]),
"cpp_link_args": self.sanitize_flags(env["LDFLAGS"]),
+ "fortran_link_args": self.sanitize_flags(env["LDFLAGS"]),
},
"properties": {
"needs_exe_wrapper": True,
diff --git a/pythonforandroid/recipes/fortran/__init__.py b/pythonforandroid/recipes/fortran/__init__.py
new file mode 100644
index 0000000000..78d97cbc64
--- /dev/null
+++ b/pythonforandroid/recipes/fortran/__init__.py
@@ -0,0 +1,188 @@
+import os
+import subprocess
+import shutil
+import sh
+from pathlib import Path
+from os.path import join
+from pythonforandroid.recipe import Recipe
+from pythonforandroid.recommendations import read_ndk_version
+from pythonforandroid.logger import info, shprint, info_main
+from pythonforandroid.util import ensure_dir
+import hashlib
+
+FLANG_FILES = {
+ "package-flang-aarch64.tar.bz2": "775f362c758abe8d3173edc7be9ced3730ff14c64d44743017c3af7ceb0a6610",
+ "package-flang-host.tar.bz2": "04fe24d67ee7eb5a4223299c610013585e75c56467e4b185ed929a3d17e3d077",
+ "package-flang-x86_64.tar.bz2": "2061a0e3179f4afa55516ce3858582d25ea7b108ff762d9fb4ec8a03b49b36d2",
+ "package-install.tar.bz2": "d37dc6a58b495807f015c7fec08a57ff95d52ad0d0553cbf573b0215d8a1707c",
+}
+
+
+class GFortranRecipe(Recipe):
+ # flang support in NDK by @licy183 (on github)
+ name = "fortran"
+ toolchain_ver = 0
+ url = "https://github.com/licy183/ndk-toolchain-clang-with-flang/releases/download/"
+
+ def match_sha256(self, file_path, expected_hash):
+ sha256 = hashlib.sha256()
+ with open(file_path, "rb") as f:
+ for chunk in iter(lambda: f.read(8192), b""):
+ sha256.update(chunk)
+ file_hash = sha256.hexdigest()
+ return file_hash == expected_hash
+
+ @property
+ def ndk_version(self):
+ ndk_version = read_ndk_version(self.ctx.ndk_dir)
+ minor_to_letter = {0: ""}
+ minor_to_letter.update(
+ {n + 1: chr(i) for n, i in enumerate(range(ord("b"), ord("b") + 25))}
+ )
+ return f"{ndk_version.major}{minor_to_letter[ndk_version.minor]}"
+
+ def get_cache_dir(self):
+ dir_name = self.get_dir_name()
+ return join(self.ctx.build_dir, "other_builds", dir_name)
+
+ def get_fortran_dir(self):
+ toolchain_name = f"android-r{self.ndk_version}-api-{self.ctx.ndk_api}"
+ return join(
+ self.get_cache_dir(), f"{toolchain_name}-flang-v{self.toolchain_ver}"
+ )
+
+ def get_incomplete_files(self):
+ incomplete_files = []
+ cache_dir = self.get_cache_dir()
+ for file, sha256sum in FLANG_FILES.items():
+ _file = join(cache_dir, file)
+ if not (os.path.exists(_file) and self.match_sha256(_file, sha256sum)):
+ incomplete_files.append(file)
+ return incomplete_files
+
+ def download_if_necessary(self):
+ assert self.ndk_version == "27c"
+ if len(self.get_incomplete_files()) == 0:
+ return
+ self.download()
+
+ def download(self):
+ cache_dir = self.get_cache_dir()
+ ensure_dir(cache_dir)
+ for file in self.get_incomplete_files():
+ _file = join(cache_dir, file)
+ if os.path.exists(_file):
+ os.remove(_file)
+ self.download_file(f"{self.url}r{join(self.ndk_version, file)}", _file)
+
+ def extract_tar(self, file_path: Path, dest: Path, strip=1):
+ shprint(
+ sh.tar,
+ "xf",
+ str(file_path),
+ "--strip-components",
+ str(strip),
+ "-C",
+ str(dest) if dest else ".",
+ )
+
+ def create_flang_wrapper(self, path: Path, target: str):
+ script = f"""#!/usr/bin/env bash
+if [ "$1" != "-cpp" ] && [ "$1" != "-fc1" ]; then
+ `dirname $0`/flang-new --target={target}{self.ctx.ndk_api} -D__ANDROID_API__={self.ctx.ndk_api} "$@"
+else
+ `dirname $0`/flang-new "$@"
+fi
+"""
+ path.write_text(script)
+ path.chmod(0o755)
+
+ def unpack(self, arch):
+ info_main("Unpacking fortran")
+
+ flang_folder = self.get_fortran_dir()
+ if os.path.exists(flang_folder):
+ info("{} is already unpacked, skipping".format(self.name))
+ return
+
+ toolchain_path = Path(
+ join(self.ctx.ndk_dir, "toolchains/llvm/prebuilt/linux-x86_64")
+ )
+ cache_dir = Path(os.path.abspath(self.get_cache_dir()))
+
+ # clean tmp folder
+ tmp_folder = Path(os.path.abspath(f"{flang_folder}-tmp"))
+ shutil.rmtree(tmp_folder, ignore_errors=True)
+ tmp_folder.mkdir(parents=True)
+ os.chdir(tmp_folder)
+
+ self.extract_tar(cache_dir / "package-install.tar.bz2", None, strip=4)
+ self.extract_tar(cache_dir / "package-flang-host.tar.bz2", None)
+
+ sysroot_path = tmp_folder / "sysroot"
+ shutil.copytree(toolchain_path / "sysroot", sysroot_path)
+
+ self.extract_tar(
+ cache_dir / "package-flang-aarch64.tar.bz2",
+ sysroot_path / "usr/lib/aarch64-linux-android",
+ )
+ self.extract_tar(
+ cache_dir / "package-flang-x86_64.tar.bz2",
+ sysroot_path / "usr/lib/x86_64-linux-android",
+ )
+
+ # Fix lib/clang paths
+ version_output = subprocess.check_output(
+ [str(tmp_folder / "bin/clang"), "--version"], text=True
+ )
+ clang_version = next(
+ (line for line in version_output.splitlines() if "clang version" in line),
+ "",
+ )
+ major_ver = clang_version.split("clang version ")[-1].split(".")[0]
+
+ lib_path = tmp_folder / f"lib/clang/{major_ver}/lib"
+ src_lib_path = toolchain_path / f"lib/clang/{major_ver}/lib"
+ shutil.rmtree(lib_path, ignore_errors=True)
+ lib_path.mkdir(parents=True)
+
+ for item in src_lib_path.iterdir():
+ shprint(sh.cp, "-r", str(item), str(lib_path))
+
+ # Create flang wrappers
+ targets = [
+ "aarch64-linux-android",
+ "armv7a-linux-androideabi",
+ "i686-linux-android",
+ "x86_64-linux-android",
+ ]
+
+ for target in targets:
+ wrapper_path = tmp_folder / f"bin/{target}-flang"
+ self.create_flang_wrapper(wrapper_path, target)
+ shutil.copy(
+ wrapper_path, tmp_folder / f"bin/{target}{self.ctx.ndk_api}-flang"
+ )
+
+ tmp_folder.rename(flang_folder)
+
+ @property
+ def bin_path(self):
+ return f"{self.get_fortran_dir()}/bin"
+
+ def get_host_platform(self, arch):
+ return {
+ "arm64-v8a": "aarch64-linux-android",
+ "armeabi-v7a": "armv7a-linux-androideabi",
+ "x86_64": "x86_64-linux-android",
+ "x86": "i686-linux-android",
+ }[arch]
+
+ def get_fortran_bin(self, arch):
+ return join(self.bin_path, f"{self.get_host_platform(arch)}-flang")
+
+ def get_fortran_flags(self, arch):
+ return f"--target={self.get_host_platform(arch)}{self.ctx.ndk_api} -D__ANDROID_API__={self.ctx.ndk_api}"
+
+
+recipe = GFortranRecipe()
diff --git a/pythonforandroid/recipes/lapack/__init__.py b/pythonforandroid/recipes/lapack/__init__.py
deleted file mode 100644
index b6124dc285..0000000000
--- a/pythonforandroid/recipes/lapack/__init__.py
+++ /dev/null
@@ -1,80 +0,0 @@
-'''
-known to build with cmake version 3.23.2 and NDK r21e.
-See https://gitlab.kitware.com/cmake/cmake/-/issues/18739
-'''
-
-from pythonforandroid.recipe import Recipe
-from pythonforandroid.logger import shprint
-from pythonforandroid.util import current_directory, ensure_dir, BuildInterruptingException
-from multiprocessing import cpu_count
-from os.path import join
-import sh
-import shutil
-from os import environ
-from pythonforandroid.util import build_platform, rmdir
-
-arch_to_sysroot = {'armeabi': 'arm', 'armeabi-v7a': 'arm', 'arm64-v8a': 'arm64'}
-
-
-def arch_to_toolchain(arch):
- if 'arm' in arch.arch:
- return arch.command_prefix
- return arch.arch
-
-
-class LapackRecipe(Recipe):
-
- name = 'lapack'
- version = 'v3.10.1'
- url = 'https://github.com/Reference-LAPACK/lapack/archive/{version}.tar.gz'
- libdir = 'build/install/lib'
- built_libraries = {'libblas.so': libdir, 'liblapack.so': libdir, 'libcblas.so': libdir}
-
- def get_recipe_env(self, arch):
- env = super().get_recipe_env(arch)
-
- ndk_dir = environ.get("LEGACY_NDK")
- if ndk_dir is None:
- raise BuildInterruptingException("Please set the environment variable 'LEGACY_NDK' to point to a NDK location with gcc/gfortran support (supported NDK version: 'r21e')")
-
- GCC_VER = '4.9'
- HOST = build_platform
-
- sysroot_suffix = arch_to_sysroot.get(arch.arch, arch.arch)
- sysroot = f"{ndk_dir}/platforms/{env['NDK_API']}/arch-{sysroot_suffix}"
- FC = f"{ndk_dir}/toolchains/{arch_to_toolchain(arch)}-{GCC_VER}/prebuilt/{HOST}/bin/{arch.command_prefix}-gfortran"
- env['FC'] = f'{FC} --sysroot={sysroot}'
- if shutil.which(FC) is None:
- raise BuildInterruptingException(f"{FC} not found. See https://github.com/mzakharo/android-gfortran")
- return env
-
- def build_arch(self, arch):
- source_dir = self.get_build_dir(arch.arch)
- build_target = join(source_dir, 'build')
- install_target = join(build_target, 'install')
-
- ensure_dir(build_target)
- with current_directory(build_target):
- env = self.get_recipe_env(arch)
- ndk_dir = environ["LEGACY_NDK"]
- rmdir('CMakeFiles')
- shprint(sh.rm, '-f', 'CMakeCache.txt', _env=env)
- opts = [
- '-DCMAKE_SYSTEM_NAME=Android',
- '-DCMAKE_POSITION_INDEPENDENT_CODE=1',
- '-DCMAKE_ANDROID_ARCH_ABI={arch}'.format(arch=arch.arch),
- '-DCMAKE_ANDROID_NDK=' + ndk_dir,
- '-DCMAKE_ANDROID_API={api}'.format(api=self.ctx.ndk_api),
- '-DCMAKE_BUILD_TYPE=Release',
- '-DCMAKE_INSTALL_PREFIX={}'.format(install_target),
- '-DCBLAS=ON',
- '-DBUILD_SHARED_LIBS=ON',
- ]
- if arch.arch == 'armeabi-v7a':
- opts.append('-DCMAKE_ANDROID_ARM_NEON=ON')
- shprint(sh.cmake, source_dir, *opts, _env=env)
- shprint(sh.make, '-j' + str(cpu_count()), _env=env)
- shprint(sh.make, 'install', _env=env)
-
-
-recipe = LapackRecipe()
diff --git a/pythonforandroid/recipes/libopenblas/__init__.py b/pythonforandroid/recipes/libopenblas/__init__.py
new file mode 100644
index 0000000000..e88feb6686
--- /dev/null
+++ b/pythonforandroid/recipes/libopenblas/__init__.py
@@ -0,0 +1,50 @@
+from pythonforandroid.recipe import Recipe
+from pythonforandroid.logger import shprint
+from pythonforandroid.util import current_directory, ensure_dir
+from multiprocessing import cpu_count
+from os.path import join
+import sh
+from pythonforandroid.util import rmdir
+
+
+class LibOpenBlasRecipe(Recipe):
+
+ version = "0.3.29"
+ url = "https://github.com/OpenMathLib/OpenBLAS/archive/refs/tags/v{version}.tar.gz"
+ built_libraries = {"libopenblas.so": "build/lib"}
+ min_ndk_api_support = 24 # complex math functions support
+
+ def build_arch(self, arch):
+ source_dir = self.get_build_dir(arch.arch)
+ build_target = join(source_dir, "build")
+
+ ensure_dir(build_target)
+ with current_directory(build_target):
+ env = self.get_recipe_env(arch)
+ rmdir("CMakeFiles")
+ shprint(sh.rm, "-f", "CMakeCache.txt", _env=env)
+
+ opts = [
+ # default cmake options
+ "-DCMAKE_SYSTEM_NAME=Android",
+ "-DCMAKE_ANDROID_ARCH_ABI={arch}".format(arch=arch.arch),
+ "-DCMAKE_ANDROID_NDK=" + self.ctx.ndk_dir,
+ "-DCMAKE_ANDROID_API={api}".format(api=self.ctx.ndk_api),
+ "-DCMAKE_BUILD_TYPE=Release",
+ "-DBUILD_SHARED_LIBS=ON",
+ "-DC_LAPACK=ON",
+ "-DTARGET={target}".format(
+ target={
+ "arm64-v8a": "ARMV8",
+ "armeabi-v7a": "ARMV7",
+ "x86_64": "CORE2",
+ "x86": "CORE2",
+ }[arch.arch]
+ ),
+ ]
+
+ shprint(sh.cmake, source_dir, *opts, _env=env)
+ shprint(sh.make, "-j" + str(cpu_count()), _env=env)
+
+
+recipe = LibOpenBlasRecipe()
diff --git a/pythonforandroid/recipes/numpy/__init__.py b/pythonforandroid/recipes/numpy/__init__.py
index fb34c0c9f7..da0f76bdef 100644
--- a/pythonforandroid/recipes/numpy/__init__.py
+++ b/pythonforandroid/recipes/numpy/__init__.py
@@ -1,17 +1,15 @@
from pythonforandroid.recipe import Recipe, MesonRecipe
-from pythonforandroid.logger import error
from os.path import join
import shutil
-NUMPY_NDK_MESSAGE = "In order to build numpy, you must set minimum ndk api (minapi) to `24`.\n"
-
class NumpyRecipe(MesonRecipe):
- version = 'v1.26.5'
+ version = 'v2.2.4'
url = 'git+https://github.com/numpy/numpy'
hostpython_prerequisites = ["Cython>=3.0.6"] # meson does not detects venv's cython
extra_build_args = ['-Csetup-args=-Dblas=none', '-Csetup-args=-Dlapack=none']
need_stl_shared = True
+ min_ndk_api_support = 24 # NumPy requires complex math functions which were added in api 24
def get_recipe_meson_options(self, arch):
options = super().get_recipe_meson_options(arch)
@@ -36,13 +34,6 @@ def get_recipe_env(self, arch, **kwargs):
"python3", self.ctx).get_build_dir(arch.arch), "android-build", "python")
return env
- def download_if_necessary(self):
- # NumPy requires complex math functions which were added in api 24
- if self.ctx.ndk_api < 24:
- error(NUMPY_NDK_MESSAGE)
- exit(1)
- super().download_if_necessary()
-
def build_arch(self, arch):
super().build_arch(arch)
self.restore_hostpython_prerequisites(["cython"])
diff --git a/pythonforandroid/recipes/pandas/__init__.py b/pythonforandroid/recipes/pandas/__init__.py
index 3f56adef6c..a656649c68 100644
--- a/pythonforandroid/recipes/pandas/__init__.py
+++ b/pythonforandroid/recipes/pandas/__init__.py
@@ -3,10 +3,10 @@
class PandasRecipe(MesonRecipe):
- version = 'v2.2.1'
+ version = 'v2.2.3'
url = 'git+https://github.com/pandas-dev/pandas' # noqa
depends = ['numpy', 'libbz2', 'liblzma']
- hostpython_prerequisites = ["Cython~=3.0.5"] # meson does not detects venv's cython
+ hostpython_prerequisites = ["Cython==3.0.5"] # meson does not detects venv's cython
patches = ['fix_numpy_includes.patch']
python_depends = ['python-dateutil', 'pytz']
need_stl_shared = True
@@ -17,7 +17,7 @@ def get_recipe_env(self, arch, **kwargs):
# because we need some includes generated at numpy's compile time
env['NUMPY_INCLUDES'] = join(
- self.ctx.get_python_install_dir(arch.arch), "numpy/core/include",
+ self.ctx.get_python_install_dir(arch.arch), "numpy/_core/include",
)
env["PYTHON_INCLUDE_DIR"] = self.ctx.python_recipe.include_root(arch)
diff --git a/pythonforandroid/recipes/python3/__init__.py b/pythonforandroid/recipes/python3/__init__.py
index 2334db6add..6127762e5a 100644
--- a/pythonforandroid/recipes/python3/__init__.py
+++ b/pythonforandroid/recipes/python3/__init__.py
@@ -141,7 +141,7 @@ class Python3Recipe(TargetPythonRecipe):
site_packages_dir_blacklist = {
'__pycache__',
- 'tests'
+ # 'tests'
}
'''The directories from site packages dir that we don't want to be included
in our python bundle.'''
diff --git a/pythonforandroid/recipes/scipy/__init__.py b/pythonforandroid/recipes/scipy/__init__.py
index 242ca04234..12e807cde8 100644
--- a/pythonforandroid/recipes/scipy/__init__.py
+++ b/pythonforandroid/recipes/scipy/__init__.py
@@ -1,91 +1,58 @@
-from multiprocessing import cpu_count
-from os.path import join
-from os import environ
-import sh
-from pythonforandroid.logger import shprint
-from pythonforandroid.recipe import CompiledComponentsPythonRecipe, Recipe
-from pythonforandroid.util import build_platform, current_directory
+from os.path import join, dirname, basename
+from pythonforandroid.recipe import MesonRecipe, Recipe
+from pathlib import Path
-def arch_to_toolchain(arch):
- if 'arm' in arch.arch:
- return arch.command_prefix
- return arch.arch
+class ScipyRecipe(MesonRecipe):
-
-class ScipyRecipe(CompiledComponentsPythonRecipe):
-
- version = 'maintenance/1.11.x'
- url = 'git+https://github.com/scipy/scipy.git'
- git_commit = 'b430bf54b5064465983813e2cfef3fcb86c3df07' # version 1.11.3
- site_packages_name = 'scipy'
- hostpython_prerequisites = ['numpy']
- depends = ['setuptools', 'cython', 'numpy', 'lapack', 'pybind11']
- call_hostpython_via_targetpython = False
+ version = "v1.15.2"
+ url = "git+https://github.com/scipy/scipy.git"
+ hostpython_prerequisites = ["Cython>=3.0.6"]
+ depends = ["numpy", "libopenblas", "fortran"]
need_stl_shared = True
- patches = ["setup.py.patch"]
-
- def build_compiled_components(self, arch):
- self.setup_extra_args = ['-j', str(cpu_count())]
- super().build_compiled_components(arch)
- self.setup_extra_args = []
-
- def rebuild_compiled_components(self, arch, env):
- self.setup_extra_args = ['-j', str(cpu_count())]
- super().rebuild_compiled_components(arch, env)
- self.setup_extra_args = []
-
- def download_file(self, url, target, cwd=None):
- super().download_file(url, target, cwd=cwd)
- with current_directory(target):
- shprint(sh.git, 'fetch', '--unshallow')
- shprint(sh.git, 'checkout', self.git_commit)
-
- def get_recipe_env(self, arch):
- env = super().get_recipe_env(arch)
+ meson_version = "1.5.0"
+ hostpython_prerequisites = ["numpy"]
+ patches = ["meson.patch"]
+
+ def get_recipe_meson_options(self, arch):
+ options = super().get_recipe_meson_options(arch)
+ options["binaries"]["python"] = self.ctx.python_recipe.python_exe
+ options["binaries"]["fortran"] = self.place_wrapper(arch)
+ options["properties"]["numpy-include-dir"] = join(
+ self.ctx.get_python_install_dir(arch.arch), "numpy/_core/include"
+ )
+ self.ensure_args(
+ "-Csetup-args=-Dblas=openblas",
+ "-Csetup-args=-Dlapack=openblas",
+ f"-Csetup-args=-Dopenblas_libdir={self.ctx.get_libs_dir(arch.arch)}",
+ f'-Csetup-args=-Dopenblas_incldir={join(Recipe.get_recipe("libopenblas", self.ctx).get_build_dir(arch.arch), "build")}',
+ "-Csetup-args=-Duse-pythran=false",
+ )
+ return options
+
+ def place_wrapper(self, arch):
+ compiler = Recipe.get_recipe("fortran", self.ctx).get_fortran_bin(arch.arch)
+ file = join(self.get_recipe_dir(), "wrapper.py")
+ with open(file, "r") as _file:
+ data = _file.read()
+ _file.close()
+ data = data.replace("@COMPILER@", compiler)
+ # custom compiler
+ # taken from: https://github.com/termux/termux-packages/blob/master/packages/python-scipy/
+ m_compiler = Path(join(dirname(compiler), basename(compiler) + "-scipy"))
+ m_compiler.write_text(data)
+ m_compiler.chmod(0o755)
+ self.patch_shebang(str(m_compiler), self.real_hostpython_location)
+ return str(m_compiler)
+
+ def get_recipe_env(self, arch, **kwargs):
+ env = super().get_recipe_env(arch, **kwargs)
arch_env = arch.get_env()
-
- env['LDFLAGS'] = arch_env['LDFLAGS']
- env['LDFLAGS'] += ' -L{} -lpython{}'.format(
+ env["LDFLAGS"] = arch_env["LDFLAGS"]
+ env["LDFLAGS"] += " -L{} -lpython{}".format(
self.ctx.python_recipe.link_root(arch.arch),
self.ctx.python_recipe.link_version,
)
-
- ndk_dir = environ["LEGACY_NDK"]
- GCC_VER = '4.9'
- HOST = build_platform
- suffix = '64' if '64' in arch.arch else ''
-
- prefix = arch.command_prefix
- CLANG_BIN = f'{ndk_dir}/toolchains/llvm/prebuilt/{HOST}/bin/'
- GCC = f'{ndk_dir}/toolchains/{arch_to_toolchain(arch)}-{GCC_VER}/prebuilt/{HOST}'
- libgfortran = f'{GCC}/{prefix}/lib{suffix}'
- numpylib = self.ctx.get_python_install_dir(arch.arch) + '/numpy'
- arch_cflags = ' '.join(arch.arch_cflags)
- LDSHARED_opts = f'-target {arch.target} {arch_cflags} ' + ' '.join(arch.common_ldshared)
-
- # TODO: add pythran support
- env['SCIPY_USE_PYTHRAN'] = '0'
-
- lapack_dir = join(Recipe.get_recipe('lapack', self.ctx).get_build_dir(arch.arch), 'build', 'install')
- env['LAPACK'] = f'{lapack_dir}/lib'
- env['BLAS'] = env['LAPACK']
-
- # compilers
- env['F77'] = f'{GCC}/bin/{prefix}-gfortran'
- env['F90'] = f'{GCC}/bin/{prefix}-gfortran'
- env['CC'] = f'{CLANG_BIN}clang -target {arch.target} {arch_cflags}'
- env['CXX'] = f'{CLANG_BIN}clang++ -target {arch.target} {arch_cflags}'
-
- # scipy expects ldshared to be a single executable without options
- env['LDSHARED'] = f'{CLANG_BIN}/clang'
-
- # erase the default NDK C++ include options
- env['CPPFLAGS'] = '-DANDROID'
-
- # configure linker
- env['LDFLAGS'] += f' {LDSHARED_opts} -L{libgfortran} -L{numpylib}/core/lib -L{numpylib}/random/lib'
- env['LDFLAGS'] += f' -l{self.stl_lib_name}'
return env
diff --git a/pythonforandroid/recipes/scipy/meson.patch b/pythonforandroid/recipes/scipy/meson.patch
new file mode 100644
index 0000000000..1fa91e9276
--- /dev/null
+++ b/pythonforandroid/recipes/scipy/meson.patch
@@ -0,0 +1,44 @@
+diff '--color=auto' -uNr scipy.git/meson.options scipy.git.patch/meson.options
+--- scipy.git/meson.options 2025-03-27 02:55:14.586853766 +0530
++++ scipy.git.patch/meson.options 2025-03-27 02:07:29.736674085 +0530
+@@ -2,6 +2,8 @@
+ description: 'option for BLAS library switching')
+ option('lapack', type: 'string', value: 'openblas',
+ description: 'option for LAPACK library switching')
++option('openblas_incldir', type: 'string', value: '', description: 'OpenBLAS include directory')
++option('openblas_libdir', type: 'string', value: '', description: 'OpenBLAS library directory')
+ option('use-g77-abi', type: 'boolean', value: false,
+ description: 'If set to true, forces using g77 compatibility wrappers ' +
+ 'for LAPACK functions. The default is to use gfortran ' +
+diff '--color=auto' -uNr scipy.git/scipy/meson.build scipy.git.patch/scipy/meson.build
+--- scipy.git/scipy/meson.build 2025-03-27 02:55:14.632428649 +0530
++++ scipy.git.patch/scipy/meson.build 2025-03-27 11:25:33.756445056 +0530
+@@ -268,10 +268,18 @@
+ endif
+ endif
+
++openblas_inc = get_option('openblas_incldir')
++openblas_lib = get_option('openblas_libdir')
++
++openblas_dep = declare_dependency(
++ include_directories: include_directories(openblas_inc),
++ link_args: ['-L' + openblas_lib, '-lopenblas']
++)
++
+ # pkg-config uses a lower-case name while CMake uses a capitalized name, so try
+ # that too to make the fallback detection with CMake work
+ if blas_name == 'openblas'
+- blas = dependency(['openblas', 'OpenBLAS'])
++ blas = openblas_dep
+ elif blas_name != 'scipy-openblas' # if so, we found it already
+ blas = dependency(blas_name)
+ endif
+@@ -295,7 +303,7 @@
+ # use that - no need to run the full detection twice.
+ lapack = blas
+ elif lapack_name == 'openblas'
+- lapack = dependency(['openblas', 'OpenBLAS'])
++ lapack = openblas_dep
+ else
+ lapack = dependency(lapack_name)
+ endif
diff --git a/pythonforandroid/recipes/scipy/setup.py.patch b/pythonforandroid/recipes/scipy/setup.py.patch
deleted file mode 100644
index 9fbc0ab5fb..0000000000
--- a/pythonforandroid/recipes/scipy/setup.py.patch
+++ /dev/null
@@ -1,1098 +0,0 @@
-diff '--color=auto' -uNr scipy/_setup.py scipy.mod/_setup.py
---- scipy/_setup.py 2023-10-30 19:20:36.545524745 +0530
-+++ scipy.mod/_setup.py 1970-01-01 05:30:00.000000000 +0530
-@@ -1,545 +0,0 @@
--#!/usr/bin/env python
--"""SciPy: Scientific Library for Python
--
--SciPy (pronounced "Sigh Pie") is open-source software for mathematics,
--science, and engineering. The SciPy library
--depends on NumPy, which provides convenient and fast N-dimensional
--array manipulation. The SciPy library is built to work with NumPy
--arrays, and provides many user-friendly and efficient numerical
--routines such as routines for numerical integration and optimization.
--Together, they run on all popular operating systems, are quick to
--install, and are free of charge. NumPy and SciPy are easy to use,
--but powerful enough to be depended upon by some of the world's
--leading scientists and engineers. If you need to manipulate
--numbers on a computer and display or publish the results,
--give SciPy a try!
--
--"""
--
--
--# IMPORTANT:
--#
--# THIS FILE IS INTENTIONALLY RENAMED FROM setup.py TO _setup.py
--# IT IS ONLY KEPT IN THE REPO BECAUSE conda-forge STILL NEEDS IT
--# FOR BUILDING SCIPY ON WINDOWS. IT SHOULD NOT BE USED BY ANYONE
--# ELSE. USE `pip install .` OR ANOTHER INSTALL COMMAND USING A
--# BUILD FRONTEND LIKE pip OR pypa/build TO INSTALL SCIPY FROM SOURCE.
--#
--# SEE http://scipy.github.io/devdocs/building/index.html FOR BUILD
--# INSTRUCTIONS.
--
--
--DOCLINES = (__doc__ or '').split("\n")
--
--import os
--import sys
--import subprocess
--import textwrap
--import warnings
--import sysconfig
--from tools.version_utils import write_version_py, get_version_info
--from tools.version_utils import IS_RELEASE_BRANCH
--import importlib
--
--
--if sys.version_info[:2] < (3, 9):
-- raise RuntimeError("Python version >= 3.9 required.")
--
--import builtins
--
--
--CLASSIFIERS = """\
--Development Status :: 5 - Production/Stable
--Intended Audience :: Science/Research
--Intended Audience :: Developers
--License :: OSI Approved :: BSD License
--Programming Language :: C
--Programming Language :: Python
--Programming Language :: Python :: 3
--Programming Language :: Python :: 3.9
--Programming Language :: Python :: 3.10
--Programming Language :: Python :: 3.11
--Topic :: Software Development :: Libraries
--Topic :: Scientific/Engineering
--Operating System :: Microsoft :: Windows
--Operating System :: POSIX :: Linux
--Operating System :: POSIX
--Operating System :: Unix
--Operating System :: MacOS
--
--"""
--
--
--# BEFORE importing setuptools, remove MANIFEST. Otherwise it may not be
--# properly updated when the contents of directories change (true for distutils,
--# not sure about setuptools).
--if os.path.exists('MANIFEST'):
-- os.remove('MANIFEST')
--
--# This is a bit hackish: we are setting a global variable so that the main
--# scipy __init__ can detect if it is being loaded by the setup routine, to
--# avoid attempting to load components that aren't built yet. While ugly, it's
--# a lot more robust than what was previously being used.
--builtins.__SCIPY_SETUP__ = True
--
--
--def check_submodules():
-- """ verify that the submodules are checked out and clean
-- use `git submodule update --init`; on failure
-- """
-- if not os.path.exists('.git'):
-- return
-- with open('.gitmodules') as f:
-- for l in f:
-- if 'path' in l:
-- p = l.split('=')[-1].strip()
-- if not os.path.exists(p):
-- raise ValueError('Submodule %s missing' % p)
--
--
-- proc = subprocess.Popen(['git', 'submodule', 'status'],
-- stdout=subprocess.PIPE)
-- status, _ = proc.communicate()
-- status = status.decode("ascii", "replace")
-- for line in status.splitlines():
-- if line.startswith('-') or line.startswith('+'):
-- raise ValueError('Submodule not clean: %s' % line)
--
--
--class concat_license_files():
-- """Merge LICENSE.txt and LICENSES_bundled.txt for sdist creation
--
-- Done this way to keep LICENSE.txt in repo as exact BSD 3-clause (see
-- NumPy gh-13447). This makes GitHub state correctly how SciPy is licensed.
-- """
-- def __init__(self):
-- self.f1 = 'LICENSE.txt'
-- self.f2 = 'LICENSES_bundled.txt'
--
-- def __enter__(self):
-- """Concatenate files and remove LICENSES_bundled.txt"""
-- with open(self.f1, 'r') as f1:
-- self.bsd_text = f1.read()
--
-- with open(self.f1, 'a') as f1:
-- with open(self.f2, 'r') as f2:
-- self.bundled_text = f2.read()
-- f1.write('\n\n')
-- f1.write(self.bundled_text)
--
-- def __exit__(self, exception_type, exception_value, traceback):
-- """Restore content of both files"""
-- with open(self.f1, 'w') as f:
-- f.write(self.bsd_text)
--
--
--from distutils.command.sdist import sdist
--class sdist_checked(sdist):
-- """ check submodules on sdist to prevent incomplete tarballs """
-- def run(self):
-- check_submodules()
-- with concat_license_files():
-- sdist.run(self)
--
--
--def get_build_ext_override():
-- """
-- Custom build_ext command to tweak extension building.
-- """
-- from numpy.distutils.command.build_ext import build_ext as npy_build_ext
-- if int(os.environ.get('SCIPY_USE_PYTHRAN', 1)):
-- try:
-- import pythran
-- from pythran.dist import PythranBuildExt
-- except ImportError:
-- BaseBuildExt = npy_build_ext
-- else:
-- BaseBuildExt = PythranBuildExt[npy_build_ext]
-- _pep440 = importlib.import_module('scipy._lib._pep440')
-- if _pep440.parse(pythran.__version__) < _pep440.Version('0.11.0'):
-- raise RuntimeError("The installed `pythran` is too old, >= "
-- "0.11.0 is needed, {} detected. Please "
-- "upgrade Pythran, or use `export "
-- "SCIPY_USE_PYTHRAN=0`.".format(
-- pythran.__version__))
-- else:
-- BaseBuildExt = npy_build_ext
--
-- class build_ext(BaseBuildExt):
-- def finalize_options(self):
-- super().finalize_options()
--
-- # Disable distutils parallel build, due to race conditions
-- # in numpy.distutils (Numpy issue gh-15957)
-- if self.parallel:
-- print("NOTE: -j build option not supported. Set NPY_NUM_BUILD_JOBS=4 "
-- "for parallel build.")
-- self.parallel = None
--
-- def build_extension(self, ext):
-- # When compiling with GNU compilers, use a version script to
-- # hide symbols during linking.
-- if self.__is_using_gnu_linker(ext):
-- export_symbols = self.get_export_symbols(ext)
-- text = '{global: %s; local: *; };' % (';'.join(export_symbols),)
--
-- script_fn = os.path.join(self.build_temp, 'link-version-{}.map'.format(ext.name))
-- with open(script_fn, 'w') as f:
-- f.write(text)
-- # line below fixes gh-8680
-- ext.extra_link_args = [arg for arg in ext.extra_link_args if not "version-script" in arg]
-- ext.extra_link_args.append('-Wl,--version-script=' + script_fn)
--
-- # Allow late configuration
-- hooks = getattr(ext, '_pre_build_hook', ())
-- _run_pre_build_hooks(hooks, (self, ext))
--
-- super().build_extension(ext)
--
-- def __is_using_gnu_linker(self, ext):
-- if not sys.platform.startswith('linux'):
-- return False
--
-- # Fortran compilation with gfortran uses it also for
-- # linking. For the C compiler, we detect gcc in a similar
-- # way as distutils does it in
-- # UnixCCompiler.runtime_library_dir_option
-- if ext.language == 'f90':
-- is_gcc = (self._f90_compiler.compiler_type in ('gnu', 'gnu95'))
-- elif ext.language == 'f77':
-- is_gcc = (self._f77_compiler.compiler_type in ('gnu', 'gnu95'))
-- else:
-- is_gcc = False
-- if self.compiler.compiler_type == 'unix':
-- cc = sysconfig.get_config_var("CC")
-- if not cc:
-- cc = ""
-- compiler_name = os.path.basename(cc.split(" ")[0])
-- is_gcc = "gcc" in compiler_name or "g++" in compiler_name
-- return is_gcc and sysconfig.get_config_var('GNULD') == 'yes'
--
-- return build_ext
--
--
--def get_build_clib_override():
-- """
-- Custom build_clib command to tweak library building.
-- """
-- from numpy.distutils.command.build_clib import build_clib as old_build_clib
--
-- class build_clib(old_build_clib):
-- def finalize_options(self):
-- super().finalize_options()
--
-- # Disable parallelization (see build_ext above)
-- self.parallel = None
--
-- def build_a_library(self, build_info, lib_name, libraries):
-- # Allow late configuration
-- hooks = build_info.get('_pre_build_hook', ())
-- _run_pre_build_hooks(hooks, (self, build_info))
-- old_build_clib.build_a_library(self, build_info, lib_name, libraries)
--
-- return build_clib
--
--
--def _run_pre_build_hooks(hooks, args):
-- """Call a sequence of pre-build hooks, if any"""
-- if hooks is None:
-- hooks = ()
-- elif not hasattr(hooks, '__iter__'):
-- hooks = (hooks,)
-- for hook in hooks:
-- hook(*args)
--
--
--def generate_cython():
-- cwd = os.path.abspath(os.path.dirname(__file__))
-- print("Cythonizing sources")
-- p = subprocess.call([sys.executable,
-- os.path.join(cwd, 'tools', 'cythonize.py'),
-- 'scipy'],
-- cwd=cwd)
-- if p != 0:
-- # Could be due to a too old pip version and build isolation, check that
-- try:
-- # Note, pip may not be installed or not have been used
-- import pip
-- except (ImportError, ModuleNotFoundError):
-- raise RuntimeError("Running cythonize failed!")
-- else:
-- _pep440 = importlib.import_module('scipy._lib._pep440')
-- if _pep440.parse(pip.__version__) < _pep440.Version('18.0.0'):
-- raise RuntimeError("Cython not found or too old. Possibly due "
-- "to `pip` being too old, found version {}, "
-- "needed is >= 18.0.0.".format(
-- pip.__version__))
-- else:
-- raise RuntimeError("Running cythonize failed!")
--
--
--def parse_setuppy_commands():
-- """Check the commands and respond appropriately. Disable broken commands.
--
-- Return a boolean value for whether or not to run the build or not (avoid
-- parsing Cython and template files if False).
-- """
-- args = sys.argv[1:]
--
-- if not args:
-- # User forgot to give an argument probably, let setuptools handle that.
-- return True
--
-- info_commands = ['--help-commands', '--name', '--version', '-V',
-- '--fullname', '--author', '--author-email',
-- '--maintainer', '--maintainer-email', '--contact',
-- '--contact-email', '--url', '--license', '--description',
-- '--long-description', '--platforms', '--classifiers',
-- '--keywords', '--provides', '--requires', '--obsoletes']
--
-- for command in info_commands:
-- if command in args:
-- return False
--
-- # Note that 'alias', 'saveopts' and 'setopt' commands also seem to work
-- # fine as they are, but are usually used together with one of the commands
-- # below and not standalone. Hence they're not added to good_commands.
-- good_commands = ('develop', 'sdist', 'build', 'build_ext', 'build_py',
-- 'build_clib', 'build_scripts', 'bdist_wheel', 'bdist_rpm',
-- 'bdist_wininst', 'bdist_msi', 'bdist_mpkg')
--
-- for command in good_commands:
-- if command in args:
-- return True
--
-- # The following commands are supported, but we need to show more
-- # useful messages to the user
-- if 'install' in args:
-- print(textwrap.dedent("""
-- Note: for reliable uninstall behaviour and dependency installation
-- and uninstallation, please use pip instead of using
-- `setup.py install`:
--
-- - `pip install .` (from a git repo or downloaded source
-- release)
-- - `pip install scipy` (last SciPy release on PyPI)
--
-- """))
-- return True
--
-- if '--help' in args or '-h' in sys.argv[1]:
-- print(textwrap.dedent("""
-- SciPy-specific help
-- -------------------
--
-- To install SciPy from here with reliable uninstall, we recommend
-- that you use `pip install .`. To install the latest SciPy release
-- from PyPI, use `pip install scipy`.
--
-- For help with build/installation issues, please ask on the
-- scipy-user mailing list. If you are sure that you have run
-- into a bug, please report it at https://github.com/scipy/scipy/issues.
--
-- Setuptools commands help
-- ------------------------
-- """))
-- return False
--
--
-- # The following commands aren't supported. They can only be executed when
-- # the user explicitly adds a --force command-line argument.
-- bad_commands = dict(
-- test="""
-- `setup.py test` is not supported. Use one of the following
-- instead:
--
-- - `python runtests.py` (to build and test)
-- - `python runtests.py --no-build` (to test installed scipy)
-- - `>>> scipy.test()` (run tests for installed scipy
-- from within an interpreter)
-- """,
-- upload="""
-- `setup.py upload` is not supported, because it's insecure.
-- Instead, build what you want to upload and upload those files
-- with `twine upload -s ` instead.
-- """,
-- upload_docs="`setup.py upload_docs` is not supported",
-- easy_install="`setup.py easy_install` is not supported",
-- clean="""
-- `setup.py clean` is not supported, use one of the following instead:
--
-- - `git clean -xdf` (cleans all files)
-- - `git clean -Xdf` (cleans all versioned files, doesn't touch
-- files that aren't checked into the git repo)
-- """,
-- check="`setup.py check` is not supported",
-- register="`setup.py register` is not supported",
-- bdist_dumb="`setup.py bdist_dumb` is not supported",
-- bdist="`setup.py bdist` is not supported",
-- flake8="`setup.py flake8` is not supported, use flake8 standalone",
-- build_sphinx="`setup.py build_sphinx` is not supported, see doc/README.md",
-- )
-- bad_commands['nosetests'] = bad_commands['test']
-- for command in ('upload_docs', 'easy_install', 'bdist', 'bdist_dumb',
-- 'register', 'check', 'install_data', 'install_headers',
-- 'install_lib', 'install_scripts', ):
-- bad_commands[command] = "`setup.py %s` is not supported" % command
--
-- for command in bad_commands.keys():
-- if command in args:
-- print(textwrap.dedent(bad_commands[command]) +
-- "\nAdd `--force` to your command to use it anyway if you "
-- "must (unsupported).\n")
-- sys.exit(1)
--
-- # Commands that do more than print info, but also don't need Cython and
-- # template parsing.
-- other_commands = ['egg_info', 'install_egg_info', 'rotate']
-- for command in other_commands:
-- if command in args:
-- return False
--
-- # If we got here, we didn't detect what setup.py command was given
-- warnings.warn("Unrecognized setuptools command ('{}'), proceeding with "
-- "generating Cython sources and expanding templates".format(
-- ' '.join(sys.argv[1:])))
-- return True
--
--def check_setuppy_command():
-- run_build = parse_setuppy_commands()
-- if run_build:
-- try:
-- pkgname = 'numpy'
-- import numpy
-- pkgname = 'pybind11'
-- import pybind11
-- except ImportError as exc: # We do not have our build deps installed
-- print(textwrap.dedent(
-- """Error: '%s' must be installed before running the build.
-- """
-- % (pkgname,)))
-- sys.exit(1)
--
-- return run_build
--
--def configuration(parent_package='', top_path=None):
-- from numpy.distutils.system_info import get_info, NotFoundError
-- from numpy.distutils.misc_util import Configuration
--
-- lapack_opt = get_info('lapack_opt')
--
-- if not lapack_opt:
-- if sys.platform == "darwin":
-- msg = ('No BLAS/LAPACK libraries found. '
-- 'Note: Accelerate is no longer supported.')
-- else:
-- msg = 'No BLAS/LAPACK libraries found.'
-- msg += ("\n"
-- "To build Scipy from sources, BLAS & LAPACK libraries "
-- "need to be installed.\n"
-- "See site.cfg.example in the Scipy source directory and\n"
-- "https://docs.scipy.org/doc/scipy/dev/contributor/building.html "
-- "for details.")
-- raise NotFoundError(msg)
--
-- config = Configuration(None, parent_package, top_path)
-- config.set_options(ignore_setup_xxx_py=True,
-- assume_default_configuration=True,
-- delegate_options_to_subpackages=True,
-- quiet=True)
--
-- config.add_subpackage('scipy')
-- config.add_data_files(('scipy', '*.txt'))
--
-- config.get_version('scipy/version.py')
--
-- return config
--
--
--def setup_package():
-- # In maintenance branch, change np_maxversion to N+3 if numpy is at N
-- # Update here, in pyproject.toml, and in scipy/__init__.py
-- # Rationale: SciPy builds without deprecation warnings with N; deprecations
-- # in N+1 will turn into errors in N+3
-- # For Python versions, if releases is (e.g.) <=3.9.x, set bound to 3.10
-- np_minversion = '1.21.6'
-- np_maxversion = '1.28.0'
-- python_minversion = '3.9'
-- python_maxversion = '3.13'
-- if IS_RELEASE_BRANCH:
-- req_np = 'numpy>={},<{}'.format(np_minversion, np_maxversion)
-- req_py = '>={},<{}'.format(python_minversion, python_maxversion)
-- else:
-- req_np = 'numpy>={}'.format(np_minversion)
-- req_py = '>={}'.format(python_minversion)
--
-- # Rewrite the version file every time
-- write_version_py('.')
--
-- cmdclass = {'sdist': sdist_checked}
--
-- metadata = dict(
-- name='scipy',
-- maintainer="SciPy Developers",
-- maintainer_email="scipy-dev@python.org",
-- description=DOCLINES[0],
-- long_description="\n".join(DOCLINES[2:]),
-- url="https://www.scipy.org",
-- download_url="https://github.com/scipy/scipy/releases",
-- project_urls={
-- "Bug Tracker": "https://github.com/scipy/scipy/issues",
-- "Documentation": "https://docs.scipy.org/doc/scipy/reference/",
-- "Source Code": "https://github.com/scipy/scipy",
-- },
-- license='BSD',
-- cmdclass=cmdclass,
-- classifiers=[_f for _f in CLASSIFIERS.split('\n') if _f],
-- platforms=["Windows", "Linux", "Solaris", "Mac OS-X", "Unix"],
-- install_requires=[req_np],
-- python_requires=req_py,
-- zip_safe=False,
-- )
--
-- if "--force" in sys.argv:
-- run_build = True
-- sys.argv.remove('--force')
-- else:
-- # Raise errors for unsupported commands, improve help output, etc.
-- run_build = check_setuppy_command()
--
-- # Disable OSX Accelerate, it has too old LAPACK
-- os.environ['ACCELERATE'] = 'None'
--
-- # This import is here because it needs to be done before importing setup()
-- # from numpy.distutils, but after the MANIFEST removing and sdist import
-- # higher up in this file.
-- from setuptools import setup
--
-- if run_build:
-- from numpy.distutils.core import setup
--
-- # Customize extension building
-- cmdclass['build_ext'] = get_build_ext_override()
-- cmdclass['build_clib'] = get_build_clib_override()
--
-- if not 'sdist' in sys.argv:
-- # Generate Cython sources, unless we're creating an sdist
-- # Cython is a build dependency, and shipping generated .c files
-- # can cause problems (see gh-14199)
-- generate_cython()
--
-- metadata['configuration'] = configuration
-- else:
-- # Don't import numpy here - non-build actions are required to succeed
-- # without NumPy for example when pip is used to install Scipy when
-- # NumPy is not yet present in the system.
--
-- # Version number is added to metadata inside configuration() if build
-- # is run.
-- metadata['version'] = get_version_info('.')[0]
--
-- setup(**metadata)
--
--
--if __name__ == '__main__':
-- setup_package()
-diff '--color=auto' -uNr scipy/setup.py scipy.mod/setup.py
---- scipy/setup.py 1970-01-01 05:30:00.000000000 +0530
-+++ scipy.mod/setup.py 2023-10-30 19:22:02.921729484 +0530
-@@ -0,0 +1,545 @@
-+#!/usr/bin/env python
-+"""SciPy: Scientific Library for Python
-+
-+SciPy (pronounced "Sigh Pie") is open-source software for mathematics,
-+science, and engineering. The SciPy library
-+depends on NumPy, which provides convenient and fast N-dimensional
-+array manipulation. The SciPy library is built to work with NumPy
-+arrays, and provides many user-friendly and efficient numerical
-+routines such as routines for numerical integration and optimization.
-+Together, they run on all popular operating systems, are quick to
-+install, and are free of charge. NumPy and SciPy are easy to use,
-+but powerful enough to be depended upon by some of the world's
-+leading scientists and engineers. If you need to manipulate
-+numbers on a computer and display or publish the results,
-+give SciPy a try!
-+
-+"""
-+
-+
-+# IMPORTANT:
-+#
-+# THIS FILE IS INTENTIONALLY RENAMED FROM setup.py TO _setup.py
-+# IT IS ONLY KEPT IN THE REPO BECAUSE conda-forge STILL NEEDS IT
-+# FOR BUILDING SCIPY ON WINDOWS. IT SHOULD NOT BE USED BY ANYONE
-+# ELSE. USE `pip install .` OR ANOTHER INSTALL COMMAND USING A
-+# BUILD FRONTEND LIKE pip OR pypa/build TO INSTALL SCIPY FROM SOURCE.
-+#
-+# SEE http://scipy.github.io/devdocs/building/index.html FOR BUILD
-+# INSTRUCTIONS.
-+
-+
-+DOCLINES = (__doc__ or '').split("\n")
-+
-+import os
-+import sys
-+import subprocess
-+import textwrap
-+import warnings
-+import sysconfig
-+from tools.version_utils import write_version_py, get_version_info
-+from tools.version_utils import IS_RELEASE_BRANCH
-+import importlib
-+
-+
-+if sys.version_info[:2] < (3, 9):
-+ raise RuntimeError("Python version >= 3.9 required.")
-+
-+import builtins
-+
-+
-+CLASSIFIERS = """\
-+Development Status :: 5 - Production/Stable
-+Intended Audience :: Science/Research
-+Intended Audience :: Developers
-+License :: OSI Approved :: BSD License
-+Programming Language :: C
-+Programming Language :: Python
-+Programming Language :: Python :: 3
-+Programming Language :: Python :: 3.9
-+Programming Language :: Python :: 3.10
-+Programming Language :: Python :: 3.11
-+Topic :: Software Development :: Libraries
-+Topic :: Scientific/Engineering
-+Operating System :: Microsoft :: Windows
-+Operating System :: POSIX :: Linux
-+Operating System :: POSIX
-+Operating System :: Unix
-+Operating System :: MacOS
-+
-+"""
-+
-+
-+# BEFORE importing setuptools, remove MANIFEST. Otherwise it may not be
-+# properly updated when the contents of directories change (true for distutils,
-+# not sure about setuptools).
-+if os.path.exists('MANIFEST'):
-+ os.remove('MANIFEST')
-+
-+# This is a bit hackish: we are setting a global variable so that the main
-+# scipy __init__ can detect if it is being loaded by the setup routine, to
-+# avoid attempting to load components that aren't built yet. While ugly, it's
-+# a lot more robust than what was previously being used.
-+builtins.__SCIPY_SETUP__ = True
-+
-+
-+def check_submodules():
-+ """ verify that the submodules are checked out and clean
-+ use `git submodule update --init`; on failure
-+ """
-+ if not os.path.exists('.git'):
-+ return
-+ with open('.gitmodules') as f:
-+ for l in f:
-+ if 'path' in l:
-+ p = l.split('=')[-1].strip()
-+ if not os.path.exists(p):
-+ raise ValueError('Submodule %s missing' % p)
-+
-+
-+ proc = subprocess.Popen(['git', 'submodule', 'status'],
-+ stdout=subprocess.PIPE)
-+ status, _ = proc.communicate()
-+ status = status.decode("ascii", "replace")
-+ for line in status.splitlines():
-+ if line.startswith('-') or line.startswith('+'):
-+ raise ValueError('Submodule not clean: %s' % line)
-+
-+
-+class concat_license_files():
-+ """Merge LICENSE.txt and LICENSES_bundled.txt for sdist creation
-+
-+ Done this way to keep LICENSE.txt in repo as exact BSD 3-clause (see
-+ NumPy gh-13447). This makes GitHub state correctly how SciPy is licensed.
-+ """
-+ def __init__(self):
-+ self.f1 = 'LICENSE.txt'
-+ self.f2 = 'LICENSES_bundled.txt'
-+
-+ def __enter__(self):
-+ """Concatenate files and remove LICENSES_bundled.txt"""
-+ with open(self.f1, 'r') as f1:
-+ self.bsd_text = f1.read()
-+
-+ with open(self.f1, 'a') as f1:
-+ with open(self.f2, 'r') as f2:
-+ self.bundled_text = f2.read()
-+ f1.write('\n\n')
-+ f1.write(self.bundled_text)
-+
-+ def __exit__(self, exception_type, exception_value, traceback):
-+ """Restore content of both files"""
-+ with open(self.f1, 'w') as f:
-+ f.write(self.bsd_text)
-+
-+
-+from distutils.command.sdist import sdist
-+class sdist_checked(sdist):
-+ """ check submodules on sdist to prevent incomplete tarballs """
-+ def run(self):
-+ check_submodules()
-+ with concat_license_files():
-+ sdist.run(self)
-+
-+
-+def get_build_ext_override():
-+ """
-+ Custom build_ext command to tweak extension building.
-+ """
-+ from numpy.distutils.command.build_ext import build_ext as npy_build_ext
-+ if int(os.environ.get('SCIPY_USE_PYTHRAN', 1)):
-+ try:
-+ import pythran
-+ from pythran.dist import PythranBuildExt
-+ except ImportError:
-+ BaseBuildExt = npy_build_ext
-+ else:
-+ BaseBuildExt = PythranBuildExt[npy_build_ext]
-+ _pep440 = importlib.import_module('scipy._lib._pep440')
-+ if _pep440.parse(pythran.__version__) < _pep440.Version('0.11.0'):
-+ raise RuntimeError("The installed `pythran` is too old, >= "
-+ "0.11.0 is needed, {} detected. Please "
-+ "upgrade Pythran, or use `export "
-+ "SCIPY_USE_PYTHRAN=0`.".format(
-+ pythran.__version__))
-+ else:
-+ BaseBuildExt = npy_build_ext
-+
-+ class build_ext(BaseBuildExt):
-+ def finalize_options(self):
-+ super().finalize_options()
-+
-+ # Disable distutils parallel build, due to race conditions
-+ # in numpy.distutils (Numpy issue gh-15957)
-+ if self.parallel:
-+ print("NOTE: -j build option not supported. Set NPY_NUM_BUILD_JOBS=4 "
-+ "for parallel build.")
-+ self.parallel = None
-+
-+ def build_extension(self, ext):
-+ # When compiling with GNU compilers, use a version script to
-+ # hide symbols during linking.
-+ if self.__is_using_gnu_linker(ext):
-+ export_symbols = self.get_export_symbols(ext)
-+ text = '{global: %s; local: *; };' % (';'.join(export_symbols),)
-+
-+ script_fn = os.path.join(self.build_temp, 'link-version-{}.map'.format(ext.name))
-+ with open(script_fn, 'w') as f:
-+ f.write(text)
-+ # line below fixes gh-8680
-+ ext.extra_link_args = [arg for arg in ext.extra_link_args if not "version-script" in arg]
-+ ext.extra_link_args.append('-Wl,--version-script=' + script_fn)
-+
-+ # Allow late configuration
-+ hooks = getattr(ext, '_pre_build_hook', ())
-+ _run_pre_build_hooks(hooks, (self, ext))
-+
-+ super().build_extension(ext)
-+
-+ def __is_using_gnu_linker(self, ext):
-+ if not sys.platform.startswith('linux'):
-+ return False
-+
-+ # Fortran compilation with gfortran uses it also for
-+ # linking. For the C compiler, we detect gcc in a similar
-+ # way as distutils does it in
-+ # UnixCCompiler.runtime_library_dir_option
-+ if ext.language == 'f90':
-+ is_gcc = (self._f90_compiler.compiler_type in ('gnu', 'gnu95'))
-+ elif ext.language == 'f77':
-+ is_gcc = (self._f77_compiler.compiler_type in ('gnu', 'gnu95'))
-+ else:
-+ is_gcc = False
-+ if self.compiler.compiler_type == 'unix':
-+ cc = sysconfig.get_config_var("CC")
-+ if not cc:
-+ cc = ""
-+ compiler_name = os.path.basename(cc.split(" ")[0])
-+ is_gcc = "gcc" in compiler_name or "g++" in compiler_name
-+ return is_gcc and sysconfig.get_config_var('GNULD') == 'yes'
-+
-+ return build_ext
-+
-+
-+def get_build_clib_override():
-+ """
-+ Custom build_clib command to tweak library building.
-+ """
-+ from numpy.distutils.command.build_clib import build_clib as old_build_clib
-+
-+ class build_clib(old_build_clib):
-+ def finalize_options(self):
-+ super().finalize_options()
-+
-+ # Disable parallelization (see build_ext above)
-+ self.parallel = None
-+
-+ def build_a_library(self, build_info, lib_name, libraries):
-+ # Allow late configuration
-+ hooks = build_info.get('_pre_build_hook', ())
-+ _run_pre_build_hooks(hooks, (self, build_info))
-+ old_build_clib.build_a_library(self, build_info, lib_name, libraries)
-+
-+ return build_clib
-+
-+
-+def _run_pre_build_hooks(hooks, args):
-+ """Call a sequence of pre-build hooks, if any"""
-+ if hooks is None:
-+ hooks = ()
-+ elif not hasattr(hooks, '__iter__'):
-+ hooks = (hooks,)
-+ for hook in hooks:
-+ hook(*args)
-+
-+
-+def generate_cython():
-+ cwd = os.path.abspath(os.path.dirname(__file__))
-+ print("Cythonizing sources")
-+ p = subprocess.call([sys.executable,
-+ os.path.join(cwd, 'tools', 'cythonize.py'),
-+ 'scipy'],
-+ cwd=cwd)
-+ if p != 0:
-+ # Could be due to a too old pip version and build isolation, check that
-+ try:
-+ # Note, pip may not be installed or not have been used
-+ import pip
-+ except (ImportError, ModuleNotFoundError):
-+ raise RuntimeError("Running cythonize failed!")
-+ else:
-+ _pep440 = importlib.import_module('scipy._lib._pep440')
-+ if _pep440.parse(pip.__version__) < _pep440.Version('18.0.0'):
-+ raise RuntimeError("Cython not found or too old. Possibly due "
-+ "to `pip` being too old, found version {}, "
-+ "needed is >= 18.0.0.".format(
-+ pip.__version__))
-+ else:
-+ raise RuntimeError("Running cythonize failed!")
-+
-+
-+def parse_setuppy_commands():
-+ """Check the commands and respond appropriately. Disable broken commands.
-+
-+ Return a boolean value for whether or not to run the build or not (avoid
-+ parsing Cython and template files if False).
-+ """
-+ args = sys.argv[1:]
-+
-+ if not args:
-+ # User forgot to give an argument probably, let setuptools handle that.
-+ return True
-+
-+ info_commands = ['--help-commands', '--name', '--version', '-V',
-+ '--fullname', '--author', '--author-email',
-+ '--maintainer', '--maintainer-email', '--contact',
-+ '--contact-email', '--url', '--license', '--description',
-+ '--long-description', '--platforms', '--classifiers',
-+ '--keywords', '--provides', '--requires', '--obsoletes']
-+
-+ for command in info_commands:
-+ if command in args:
-+ return False
-+
-+ # Note that 'alias', 'saveopts' and 'setopt' commands also seem to work
-+ # fine as they are, but are usually used together with one of the commands
-+ # below and not standalone. Hence they're not added to good_commands.
-+ good_commands = ('develop', 'sdist', 'build', 'build_ext', 'build_py',
-+ 'build_clib', 'build_scripts', 'bdist_wheel', 'bdist_rpm',
-+ 'bdist_wininst', 'bdist_msi', 'bdist_mpkg')
-+
-+ for command in good_commands:
-+ if command in args:
-+ return True
-+
-+ # The following commands are supported, but we need to show more
-+ # useful messages to the user
-+ if 'install' in args:
-+ print(textwrap.dedent("""
-+ Note: for reliable uninstall behaviour and dependency installation
-+ and uninstallation, please use pip instead of using
-+ `setup.py install`:
-+
-+ - `pip install .` (from a git repo or downloaded source
-+ release)
-+ - `pip install scipy` (last SciPy release on PyPI)
-+
-+ """))
-+ return True
-+
-+ if '--help' in args or '-h' in sys.argv[1]:
-+ print(textwrap.dedent("""
-+ SciPy-specific help
-+ -------------------
-+
-+ To install SciPy from here with reliable uninstall, we recommend
-+ that you use `pip install .`. To install the latest SciPy release
-+ from PyPI, use `pip install scipy`.
-+
-+ For help with build/installation issues, please ask on the
-+ scipy-user mailing list. If you are sure that you have run
-+ into a bug, please report it at https://github.com/scipy/scipy/issues.
-+
-+ Setuptools commands help
-+ ------------------------
-+ """))
-+ return False
-+
-+
-+ # The following commands aren't supported. They can only be executed when
-+ # the user explicitly adds a --force command-line argument.
-+ bad_commands = dict(
-+ test="""
-+ `setup.py test` is not supported. Use one of the following
-+ instead:
-+
-+ - `python runtests.py` (to build and test)
-+ - `python runtests.py --no-build` (to test installed scipy)
-+ - `>>> scipy.test()` (run tests for installed scipy
-+ from within an interpreter)
-+ """,
-+ upload="""
-+ `setup.py upload` is not supported, because it's insecure.
-+ Instead, build what you want to upload and upload those files
-+ with `twine upload -s ` instead.
-+ """,
-+ upload_docs="`setup.py upload_docs` is not supported",
-+ easy_install="`setup.py easy_install` is not supported",
-+ clean="""
-+ `setup.py clean` is not supported, use one of the following instead:
-+
-+ - `git clean -xdf` (cleans all files)
-+ - `git clean -Xdf` (cleans all versioned files, doesn't touch
-+ files that aren't checked into the git repo)
-+ """,
-+ check="`setup.py check` is not supported",
-+ register="`setup.py register` is not supported",
-+ bdist_dumb="`setup.py bdist_dumb` is not supported",
-+ bdist="`setup.py bdist` is not supported",
-+ flake8="`setup.py flake8` is not supported, use flake8 standalone",
-+ build_sphinx="`setup.py build_sphinx` is not supported, see doc/README.md",
-+ )
-+ bad_commands['nosetests'] = bad_commands['test']
-+ for command in ('upload_docs', 'easy_install', 'bdist', 'bdist_dumb',
-+ 'register', 'check', 'install_data', 'install_headers',
-+ 'install_lib', 'install_scripts', ):
-+ bad_commands[command] = "`setup.py %s` is not supported" % command
-+
-+ for command in bad_commands.keys():
-+ if command in args:
-+ print(textwrap.dedent(bad_commands[command]) +
-+ "\nAdd `--force` to your command to use it anyway if you "
-+ "must (unsupported).\n")
-+ sys.exit(1)
-+
-+ # Commands that do more than print info, but also don't need Cython and
-+ # template parsing.
-+ other_commands = ['egg_info', 'install_egg_info', 'rotate']
-+ for command in other_commands:
-+ if command in args:
-+ return False
-+
-+ # If we got here, we didn't detect what setup.py command was given
-+ warnings.warn("Unrecognized setuptools command ('{}'), proceeding with "
-+ "generating Cython sources and expanding templates".format(
-+ ' '.join(sys.argv[1:])))
-+ return True
-+
-+def check_setuppy_command():
-+ run_build = parse_setuppy_commands()
-+ if run_build:
-+ try:
-+ pkgname = 'numpy'
-+ import numpy
-+ pkgname = 'pybind11'
-+ import pybind11
-+ except ImportError as exc: # We do not have our build deps installed
-+ print(textwrap.dedent(
-+ """Error: '%s' must be installed before running the build.
-+ """
-+ % (pkgname,)))
-+ sys.exit(1)
-+
-+ return run_build
-+
-+def configuration(parent_package='', top_path=None):
-+ from numpy.distutils.system_info import get_info, NotFoundError
-+ from numpy.distutils.misc_util import Configuration
-+
-+ lapack_opt = get_info('lapack_opt')
-+
-+ if not lapack_opt:
-+ if sys.platform == "darwin":
-+ msg = ('No BLAS/LAPACK libraries found. '
-+ 'Note: Accelerate is no longer supported.')
-+ else:
-+ msg = 'No BLAS/LAPACK libraries found.'
-+ msg += ("\n"
-+ "To build Scipy from sources, BLAS & LAPACK libraries "
-+ "need to be installed.\n"
-+ "See site.cfg.example in the Scipy source directory and\n"
-+ "https://docs.scipy.org/doc/scipy/dev/contributor/building.html "
-+ "for details.")
-+ raise NotFoundError(msg)
-+
-+ config = Configuration(None, parent_package, top_path)
-+ config.set_options(ignore_setup_xxx_py=True,
-+ assume_default_configuration=True,
-+ delegate_options_to_subpackages=True,
-+ quiet=True)
-+
-+ config.add_subpackage('scipy')
-+ config.add_data_files(('scipy', '*.txt'))
-+
-+ config.get_version('scipy/version.py')
-+
-+ return config
-+
-+
-+def setup_package():
-+ # In maintenance branch, change np_maxversion to N+3 if numpy is at N
-+ # Update here, in pyproject.toml, and in scipy/__init__.py
-+ # Rationale: SciPy builds without deprecation warnings with N; deprecations
-+ # in N+1 will turn into errors in N+3
-+ # For Python versions, if releases is (e.g.) <=3.9.x, set bound to 3.10
-+ np_minversion = '1.21.6'
-+ np_maxversion = '1.28.0'
-+ python_minversion = '3.9'
-+ python_maxversion = '3.13'
-+ if IS_RELEASE_BRANCH:
-+ req_np = 'numpy>={},<{}'.format(np_minversion, np_maxversion)
-+ req_py = '>={},<{}'.format(python_minversion, python_maxversion)
-+ else:
-+ req_np = 'numpy>={}'.format(np_minversion)
-+ req_py = '>={}'.format(python_minversion)
-+
-+ # Rewrite the version file every time
-+ write_version_py('.')
-+
-+ cmdclass = {'sdist': sdist_checked}
-+
-+ metadata = dict(
-+ name='scipy',
-+ maintainer="SciPy Developers",
-+ maintainer_email="scipy-dev@python.org",
-+ description=DOCLINES[0],
-+ long_description="\n".join(DOCLINES[2:]),
-+ url="https://www.scipy.org",
-+ download_url="https://github.com/scipy/scipy/releases",
-+ project_urls={
-+ "Bug Tracker": "https://github.com/scipy/scipy/issues",
-+ "Documentation": "https://docs.scipy.org/doc/scipy/reference/",
-+ "Source Code": "https://github.com/scipy/scipy",
-+ },
-+ license='BSD',
-+ cmdclass=cmdclass,
-+ classifiers=[_f for _f in CLASSIFIERS.split('\n') if _f],
-+ platforms=["Windows", "Linux", "Solaris", "Mac OS-X", "Unix"],
-+ install_requires=[req_np],
-+ python_requires=req_py,
-+ zip_safe=False,
-+ )
-+
-+ if "--force" in sys.argv:
-+ run_build = True
-+ sys.argv.remove('--force')
-+ else:
-+ # Raise errors for unsupported commands, improve help output, etc.
-+ run_build = check_setuppy_command()
-+
-+ # Disable OSX Accelerate, it has too old LAPACK
-+ os.environ['ACCELERATE'] = 'None'
-+
-+ # This import is here because it needs to be done before importing setup()
-+ # from numpy.distutils, but after the MANIFEST removing and sdist import
-+ # higher up in this file.
-+ from setuptools import setup
-+
-+ if run_build:
-+ from numpy.distutils.core import setup
-+
-+ # Customize extension building
-+ cmdclass['build_ext'] = get_build_ext_override()
-+ cmdclass['build_clib'] = get_build_clib_override()
-+
-+ if not 'sdist' in sys.argv:
-+ # Generate Cython sources, unless we're creating an sdist
-+ # Cython is a build dependency, and shipping generated .c files
-+ # can cause problems (see gh-14199)
-+ generate_cython()
-+
-+ metadata['configuration'] = configuration
-+ else:
-+ # Don't import numpy here - non-build actions are required to succeed
-+ # without NumPy for example when pip is used to install Scipy when
-+ # NumPy is not yet present in the system.
-+
-+ # Version number is added to metadata inside configuration() if build
-+ # is run.
-+ metadata['version'] = get_version_info('.')[0]
-+
-+ setup(**metadata)
-+
-+
-+if __name__ == '__main__':
-+ setup_package()
diff --git a/pythonforandroid/recipes/scipy/wrapper.py b/pythonforandroid/recipes/scipy/wrapper.py
new file mode 100644
index 0000000000..ca0e60d22e
--- /dev/null
+++ b/pythonforandroid/recipes/scipy/wrapper.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python3
+
+# Taken from https://github.com/termux/termux-packages/blob/master/packages/python-scipy/wrapper.py.in
+
+import os
+import subprocess
+import sys
+import typing
+
+"""
+This wrapper is used to ignore or replace some unsupported flags for flang-new.
+
+It will operate as follows:
+
+1. Ignore `-Minform=inform` and `-fdiagnostics-color`.
+ They are added by meson automatically, but are not supported by flang-new yet.
+2. Remove `-lflang` and `-lpgmath`.
+ It exists in classic-flang but doesn't exist in flang-new.
+3. Replace `-Oz` to `-O2`.
+ `-Oz` is not supported by flang-new.
+4. Replace `-module` to `-J`.
+ See https://github.com/llvm/llvm-project/issues/66969
+5. Ignore `-MD`, `-MQ file` and `-MF file`.
+ They generates files used by GNU make but we're using ninja.
+6. Ignore `-fvisibility=hidden`.
+ It is not supported by flang-new, and ignoring it will not break the functionality,
+ as scipy also uses version script for shared libraries.
+"""
+
+COMPLIER_PATH = "@COMPILER@"
+
+
+def main(argv: typing.List[str]):
+ cwd = os.getcwd()
+ argv_new = []
+ i = 0
+ while i < len(argv):
+ arg = argv[i]
+ if arg in [
+ "-Minform=inform",
+ "-lflang",
+ "-lpgmath",
+ "-MD",
+ "-fvisibility=hidden",
+ ] or arg.startswith("-fdiagnostics-color"):
+ pass
+ elif arg == "-Oz":
+ argv_new.append("-O2")
+ elif arg == "-module":
+ argv_new.append("-J")
+ elif arg in ["-MQ", "-MF"]:
+ i += 1
+ else:
+ argv_new.append(arg)
+ i += 1
+
+ args = [COMPLIER_PATH] + argv_new
+ subprocess.check_call(args, env=os.environ, cwd=cwd, text=True)
+
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/pythonforandroid/recipes/sdl2/__init__.py b/pythonforandroid/recipes/sdl2/__init__.py
index 8d5fbc2dc2..ceabeef1ed 100644
--- a/pythonforandroid/recipes/sdl2/__init__.py
+++ b/pythonforandroid/recipes/sdl2/__init__.py
@@ -6,9 +6,9 @@
class LibSDL2Recipe(BootstrapNDKRecipe):
- version = "2.28.5"
+ version = "2.30.11"
url = "https://github.com/libsdl-org/SDL/releases/download/release-{version}/SDL2-{version}.tar.gz"
- md5sum = 'a344eb827a03045c9b399e99af4af13d'
+ md5sum = 'bea190b480f6df249db29eb3bacfe41e'
dir_name = 'SDL'
diff --git a/pythonforandroid/recommendations.py b/pythonforandroid/recommendations.py
index 269a57fcf8..5584815d57 100644
--- a/pythonforandroid/recommendations.py
+++ b/pythonforandroid/recommendations.py
@@ -13,7 +13,7 @@
MAX_NDK_VERSION = 25
# DO NOT CHANGE LINE FORMAT: buildozer parses the existence of a RECOMMENDED_NDK_VERSION
-RECOMMENDED_NDK_VERSION = "25b"
+RECOMMENDED_NDK_VERSION = "27c"
NDK_DOWNLOAD_URL = "https://developer.android.com/ndk/downloads/"