diff options
| author | blackhao <13851610112@163.com> | 2025-08-22 02:51:50 -0500 |
|---|---|---|
| committer | blackhao <13851610112@163.com> | 2025-08-22 02:51:50 -0500 |
| commit | 4aab4087dc97906d0b9890035401175cdaab32d4 (patch) | |
| tree | 4e2e9d88a711ec5b1cfa02e8ac72a55183b99123 /.venv/lib/python3.12/site-packages/numpy/f2py/_backends | |
| parent | afa8f50d1d21c721dabcb31ad244610946ab65a3 (diff) | |
2.0
Diffstat (limited to '.venv/lib/python3.12/site-packages/numpy/f2py/_backends')
13 files changed, 542 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__init__.py b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__init__.py new file mode 100644 index 0000000..e91393c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__init__.py @@ -0,0 +1,9 @@ +def f2py_build_generator(name): + if name == "meson": + from ._meson import MesonBackend + return MesonBackend + elif name == "distutils": + from ._distutils import DistutilsBackend + return DistutilsBackend + else: + raise ValueError(f"Unknown backend: {name}") diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__init__.pyi b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__init__.pyi new file mode 100644 index 0000000..43625c6 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__init__.pyi @@ -0,0 +1,5 @@ +from typing import Literal as L + +from ._backend import Backend + +def f2py_build_generator(name: L["distutils", "meson"]) -> Backend: ... diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__pycache__/__init__.cpython-312.pyc Binary files differnew file mode 100644 index 0000000..2133a79 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__pycache__/__init__.cpython-312.pyc diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__pycache__/_backend.cpython-312.pyc b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__pycache__/_backend.cpython-312.pyc Binary files differnew file mode 100644 index 0000000..bd84bd4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__pycache__/_backend.cpython-312.pyc diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__pycache__/_distutils.cpython-312.pyc b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__pycache__/_distutils.cpython-312.pyc Binary files differnew file mode 100644 index 0000000..9d9594c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__pycache__/_distutils.cpython-312.pyc diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__pycache__/_meson.cpython-312.pyc b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__pycache__/_meson.cpython-312.pyc Binary files differnew file mode 100644 index 0000000..e1a5d84 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/__pycache__/_meson.cpython-312.pyc diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_backend.py b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_backend.py new file mode 100644 index 0000000..5dda400 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_backend.py @@ -0,0 +1,44 @@ +from abc import ABC, abstractmethod + + +class Backend(ABC): + def __init__( + self, + modulename, + sources, + extra_objects, + build_dir, + include_dirs, + library_dirs, + libraries, + define_macros, + undef_macros, + f2py_flags, + sysinfo_flags, + fc_flags, + flib_flags, + setup_flags, + remove_build_dir, + extra_dat, + ): + self.modulename = modulename + self.sources = sources + self.extra_objects = extra_objects + self.build_dir = build_dir + self.include_dirs = include_dirs + self.library_dirs = library_dirs + self.libraries = libraries + self.define_macros = define_macros + self.undef_macros = undef_macros + self.f2py_flags = f2py_flags + self.sysinfo_flags = sysinfo_flags + self.fc_flags = fc_flags + self.flib_flags = flib_flags + self.setup_flags = setup_flags + self.remove_build_dir = remove_build_dir + self.extra_dat = extra_dat + + @abstractmethod + def compile(self) -> None: + """Compile the wrapper.""" + pass diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_backend.pyi b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_backend.pyi new file mode 100644 index 0000000..ed24519 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_backend.pyi @@ -0,0 +1,46 @@ +import abc +from pathlib import Path +from typing import Any, Final + +class Backend(abc.ABC): + modulename: Final[str] + sources: Final[list[str | Path]] + extra_objects: Final[list[str]] + build_dir: Final[str | Path] + include_dirs: Final[list[str | Path]] + library_dirs: Final[list[str | Path]] + libraries: Final[list[str]] + define_macros: Final[list[tuple[str, str | None]]] + undef_macros: Final[list[str]] + f2py_flags: Final[list[str]] + sysinfo_flags: Final[list[str]] + fc_flags: Final[list[str]] + flib_flags: Final[list[str]] + setup_flags: Final[list[str]] + remove_build_dir: Final[bool] + extra_dat: Final[dict[str, Any]] + + def __init__( + self, + /, + modulename: str, + sources: list[str | Path], + extra_objects: list[str], + build_dir: str | Path, + include_dirs: list[str | Path], + library_dirs: list[str | Path], + libraries: list[str], + define_macros: list[tuple[str, str | None]], + undef_macros: list[str], + f2py_flags: list[str], + sysinfo_flags: list[str], + fc_flags: list[str], + flib_flags: list[str], + setup_flags: list[str], + remove_build_dir: bool, + extra_dat: dict[str, Any], + ) -> None: ... + + # + @abc.abstractmethod + def compile(self) -> None: ... diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_distutils.py b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_distutils.py new file mode 100644 index 0000000..5c8f109 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_distutils.py @@ -0,0 +1,76 @@ +import os +import shutil +import sys +import warnings + +from numpy.distutils.core import Extension, setup +from numpy.distutils.misc_util import dict_append +from numpy.distutils.system_info import get_info +from numpy.exceptions import VisibleDeprecationWarning + +from ._backend import Backend + + +class DistutilsBackend(Backend): + def __init__(sef, *args, **kwargs): + warnings.warn( + "\ndistutils has been deprecated since NumPy 1.26.x\n" + "Use the Meson backend instead, or generate wrappers" + " without -c and use a custom build script", + VisibleDeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) + + def compile(self): + num_info = {} + if num_info: + self.include_dirs.extend(num_info.get("include_dirs", [])) + ext_args = { + "name": self.modulename, + "sources": self.sources, + "include_dirs": self.include_dirs, + "library_dirs": self.library_dirs, + "libraries": self.libraries, + "define_macros": self.define_macros, + "undef_macros": self.undef_macros, + "extra_objects": self.extra_objects, + "f2py_options": self.f2py_flags, + } + + if self.sysinfo_flags: + for n in self.sysinfo_flags: + i = get_info(n) + if not i: + print( + f"No {n!r} resources found" + "in system (try `f2py --help-link`)" + ) + dict_append(ext_args, **i) + + ext = Extension(**ext_args) + + sys.argv = [sys.argv[0]] + self.setup_flags + sys.argv.extend( + [ + "build", + "--build-temp", + self.build_dir, + "--build-base", + self.build_dir, + "--build-platlib", + ".", + "--disable-optimization", + ] + ) + + if self.fc_flags: + sys.argv.extend(["config_fc"] + self.fc_flags) + if self.flib_flags: + sys.argv.extend(["build_ext"] + self.flib_flags) + + setup(ext_modules=[ext]) + + if self.remove_build_dir and os.path.exists(self.build_dir): + print(f"Removing build directory {self.build_dir}") + shutil.rmtree(self.build_dir) diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_distutils.pyi b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_distutils.pyi new file mode 100644 index 0000000..56bbf7e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_distutils.pyi @@ -0,0 +1,13 @@ +from typing_extensions import deprecated, override + +from ._backend import Backend + +class DistutilsBackend(Backend): + @deprecated( + "distutils has been deprecated since NumPy 1.26.x. Use the Meson backend instead, or generate wrappers without -c and " + "use a custom build script" + ) + # NOTE: the `sef` typo matches runtime + def __init__(sef, *args: object, **kwargs: object) -> None: ... + @override + def compile(self) -> None: ... diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_meson.py b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_meson.py new file mode 100644 index 0000000..cbd9b0e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_meson.py @@ -0,0 +1,231 @@ +import errno +import os +import re +import shutil +import subprocess +import sys +from itertools import chain +from pathlib import Path +from string import Template + +from ._backend import Backend + + +class MesonTemplate: + """Template meson build file generation class.""" + + def __init__( + self, + modulename: str, + sources: list[Path], + deps: list[str], + libraries: list[str], + library_dirs: list[Path], + include_dirs: list[Path], + object_files: list[Path], + linker_args: list[str], + fortran_args: list[str], + build_type: str, + python_exe: str, + ): + self.modulename = modulename + self.build_template_path = ( + Path(__file__).parent.absolute() / "meson.build.template" + ) + self.sources = sources + self.deps = deps + self.libraries = libraries + self.library_dirs = library_dirs + if include_dirs is not None: + self.include_dirs = include_dirs + else: + self.include_dirs = [] + self.substitutions = {} + self.objects = object_files + # Convert args to '' wrapped variant for meson + self.fortran_args = [ + f"'{x}'" if not (x.startswith("'") and x.endswith("'")) else x + for x in fortran_args + ] + self.pipeline = [ + self.initialize_template, + self.sources_substitution, + self.deps_substitution, + self.include_substitution, + self.libraries_substitution, + self.fortran_args_substitution, + ] + self.build_type = build_type + self.python_exe = python_exe + self.indent = " " * 21 + + def meson_build_template(self) -> str: + if not self.build_template_path.is_file(): + raise FileNotFoundError( + errno.ENOENT, + "Meson build template" + f" {self.build_template_path.absolute()}" + " does not exist.", + ) + return self.build_template_path.read_text() + + def initialize_template(self) -> None: + self.substitutions["modulename"] = self.modulename + self.substitutions["buildtype"] = self.build_type + self.substitutions["python"] = self.python_exe + + def sources_substitution(self) -> None: + self.substitutions["source_list"] = ",\n".join( + [f"{self.indent}'''{source}'''," for source in self.sources] + ) + + def deps_substitution(self) -> None: + self.substitutions["dep_list"] = f",\n{self.indent}".join( + [f"{self.indent}dependency('{dep}')," for dep in self.deps] + ) + + def libraries_substitution(self) -> None: + self.substitutions["lib_dir_declarations"] = "\n".join( + [ + f"lib_dir_{i} = declare_dependency(link_args : ['''-L{lib_dir}'''])" + for i, lib_dir in enumerate(self.library_dirs) + ] + ) + + self.substitutions["lib_declarations"] = "\n".join( + [ + f"{lib.replace('.', '_')} = declare_dependency(link_args : ['-l{lib}'])" + for lib in self.libraries + ] + ) + + self.substitutions["lib_list"] = f"\n{self.indent}".join( + [f"{self.indent}{lib.replace('.', '_')}," for lib in self.libraries] + ) + self.substitutions["lib_dir_list"] = f"\n{self.indent}".join( + [f"{self.indent}lib_dir_{i}," for i in range(len(self.library_dirs))] + ) + + def include_substitution(self) -> None: + self.substitutions["inc_list"] = f",\n{self.indent}".join( + [f"{self.indent}'''{inc}'''," for inc in self.include_dirs] + ) + + def fortran_args_substitution(self) -> None: + if self.fortran_args: + self.substitutions["fortran_args"] = ( + f"{self.indent}fortran_args: [{', '.join(list(self.fortran_args))}]," + ) + else: + self.substitutions["fortran_args"] = "" + + def generate_meson_build(self): + for node in self.pipeline: + node() + template = Template(self.meson_build_template()) + meson_build = template.substitute(self.substitutions) + meson_build = meson_build.replace(",,", ",") + return meson_build + + +class MesonBackend(Backend): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.dependencies = self.extra_dat.get("dependencies", []) + self.meson_build_dir = "bbdir" + self.build_type = ( + "debug" if any("debug" in flag for flag in self.fc_flags) else "release" + ) + self.fc_flags = _get_flags(self.fc_flags) + + def _move_exec_to_root(self, build_dir: Path): + walk_dir = Path(build_dir) / self.meson_build_dir + path_objects = chain( + walk_dir.glob(f"{self.modulename}*.so"), + walk_dir.glob(f"{self.modulename}*.pyd"), + walk_dir.glob(f"{self.modulename}*.dll"), + ) + # Same behavior as distutils + # https://github.com/numpy/numpy/issues/24874#issuecomment-1835632293 + for path_object in path_objects: + dest_path = Path.cwd() / path_object.name + if dest_path.exists(): + dest_path.unlink() + shutil.copy2(path_object, dest_path) + os.remove(path_object) + + def write_meson_build(self, build_dir: Path) -> None: + """Writes the meson build file at specified location""" + meson_template = MesonTemplate( + self.modulename, + self.sources, + self.dependencies, + self.libraries, + self.library_dirs, + self.include_dirs, + self.extra_objects, + self.flib_flags, + self.fc_flags, + self.build_type, + sys.executable, + ) + src = meson_template.generate_meson_build() + Path(build_dir).mkdir(parents=True, exist_ok=True) + meson_build_file = Path(build_dir) / "meson.build" + meson_build_file.write_text(src) + return meson_build_file + + def _run_subprocess_command(self, command, cwd): + subprocess.run(command, cwd=cwd, check=True) + + def run_meson(self, build_dir: Path): + setup_command = ["meson", "setup", self.meson_build_dir] + self._run_subprocess_command(setup_command, build_dir) + compile_command = ["meson", "compile", "-C", self.meson_build_dir] + self._run_subprocess_command(compile_command, build_dir) + + def compile(self) -> None: + self.sources = _prepare_sources(self.modulename, self.sources, self.build_dir) + self.write_meson_build(self.build_dir) + self.run_meson(self.build_dir) + self._move_exec_to_root(self.build_dir) + + +def _prepare_sources(mname, sources, bdir): + extended_sources = sources.copy() + Path(bdir).mkdir(parents=True, exist_ok=True) + # Copy sources + for source in sources: + if Path(source).exists() and Path(source).is_file(): + shutil.copy(source, bdir) + generated_sources = [ + Path(f"{mname}module.c"), + Path(f"{mname}-f2pywrappers2.f90"), + Path(f"{mname}-f2pywrappers.f"), + ] + bdir = Path(bdir) + for generated_source in generated_sources: + if generated_source.exists(): + shutil.copy(generated_source, bdir / generated_source.name) + extended_sources.append(generated_source.name) + generated_source.unlink() + extended_sources = [ + Path(source).name + for source in extended_sources + if not Path(source).suffix == ".pyf" + ] + return extended_sources + + +def _get_flags(fc_flags): + flag_values = [] + flag_pattern = re.compile(r"--f(77|90)flags=(.*)") + for flag in fc_flags: + match_result = flag_pattern.match(flag) + if match_result: + values = match_result.group(2).strip().split() + values = [val.strip("'\"") for val in values] + flag_values.extend(values) + # Hacky way to preserve order of flags + unique_flags = list(dict.fromkeys(flag_values)) + return unique_flags diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_meson.pyi b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_meson.pyi new file mode 100644 index 0000000..b9f9595 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_meson.pyi @@ -0,0 +1,63 @@ +from collections.abc import Callable +from pathlib import Path +from typing import Final +from typing import Literal as L + +from typing_extensions import override + +from ._backend import Backend + +class MesonTemplate: + modulename: Final[str] + build_template_path: Final[Path] + sources: Final[list[str | Path]] + deps: Final[list[str]] + libraries: Final[list[str]] + library_dirs: Final[list[str | Path]] + include_dirs: Final[list[str | Path]] + substitutions: Final[dict[str, str]] + objects: Final[list[str | Path]] + fortran_args: Final[list[str]] + pipeline: Final[list[Callable[[], None]]] + build_type: Final[str] + python_exe: Final[str] + indent: Final[str] + + def __init__( + self, + /, + modulename: str, + sources: list[Path], + deps: list[str], + libraries: list[str], + library_dirs: list[str | Path], + include_dirs: list[str | Path], + object_files: list[str | Path], + linker_args: list[str], + fortran_args: list[str], + build_type: str, + python_exe: str, + ) -> None: ... + + # + def initialize_template(self) -> None: ... + def sources_substitution(self) -> None: ... + def deps_substitution(self) -> None: ... + def libraries_substitution(self) -> None: ... + def include_substitution(self) -> None: ... + def fortran_args_substitution(self) -> None: ... + + # + def meson_build_template(self) -> str: ... + def generate_meson_build(self) -> str: ... + +class MesonBackend(Backend): + dependencies: list[str] + meson_build_dir: L["bdir"] + build_type: L["debug", "release"] + + def __init__(self, /, *args: object, **kwargs: object) -> None: ... + def write_meson_build(self, /, build_dir: Path) -> None: ... + def run_meson(self, /, build_dir: Path) -> None: ... + @override + def compile(self) -> None: ... diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/meson.build.template b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/meson.build.template new file mode 100644 index 0000000..fdcc1b1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/meson.build.template @@ -0,0 +1,55 @@ +project('${modulename}', + ['c', 'fortran'], + version : '0.1', + meson_version: '>= 1.1.0', + default_options : [ + 'warning_level=1', + 'buildtype=${buildtype}' + ]) +fc = meson.get_compiler('fortran') + +py = import('python').find_installation('''${python}''', pure: false) +py_dep = py.dependency() + +incdir_numpy = run_command(py, + ['-c', 'import os; os.chdir(".."); import numpy; print(numpy.get_include())'], + check : true +).stdout().strip() + +incdir_f2py = run_command(py, + ['-c', 'import os; os.chdir(".."); import numpy.f2py; print(numpy.f2py.get_include())'], + check : true +).stdout().strip() + +inc_np = include_directories(incdir_numpy) +np_dep = declare_dependency(include_directories: inc_np) + +incdir_f2py = incdir_numpy / '..' / '..' / 'f2py' / 'src' +inc_f2py = include_directories(incdir_f2py) +fortranobject_c = incdir_f2py / 'fortranobject.c' + +inc_np = include_directories(incdir_numpy, incdir_f2py) +# gh-25000 +quadmath_dep = fc.find_library('quadmath', required: false) + +${lib_declarations} +${lib_dir_declarations} + +py.extension_module('${modulename}', + [ +${source_list}, + fortranobject_c + ], + include_directories: [ + inc_np, +${inc_list} + ], + dependencies : [ + py_dep, + quadmath_dep, +${dep_list} +${lib_list} +${lib_dir_list} + ], +${fortran_args} + install : true) |
