aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_meson.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_meson.py')
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_meson.py205
1 files changed, 205 insertions, 0 deletions
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 00000000..f324e0f5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/_backends/_meson.py
@@ -0,0 +1,205 @@
+from __future__ import annotations
+
+import os
+import errno
+import shutil
+import subprocess
+import sys
+from pathlib import Path
+
+from ._backend import Backend
+from string import Template
+from itertools import chain
+
+import warnings
+
+
+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],
+ c_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
+ self.pipeline = [
+ self.initialize_template,
+ self.sources_substitution,
+ self.deps_substitution,
+ self.include_substitution,
+ self.libraries_substitution,
+ ]
+ self.build_type = build_type
+ self.python_exe = python_exe
+
+ 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:
+ indent = " " * 21
+ self.substitutions["source_list"] = f",\n{indent}".join(
+ [f"{indent}'{source}'" for source in self.sources]
+ )
+
+ def deps_substitution(self) -> None:
+ indent = " " * 21
+ self.substitutions["dep_list"] = f",\n{indent}".join(
+ [f"{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} = declare_dependency(link_args : ['-l{lib}'])"
+ for lib in self.libraries
+ ]
+ )
+
+ indent = " " * 21
+ self.substitutions["lib_list"] = f"\n{indent}".join(
+ [f"{indent}{lib}," for lib in self.libraries]
+ )
+ self.substitutions["lib_dir_list"] = f"\n{indent}".join(
+ [f"{indent}lib_dir_{i}," for i in range(len(self.library_dirs))]
+ )
+
+ def include_substitution(self) -> None:
+ indent = " " * 21
+ self.substitutions["inc_list"] = f",\n{indent}".join(
+ [f"{indent}'{inc}'" for inc in self.include_dirs]
+ )
+
+ def generate_meson_build(self):
+ for node in self.pipeline:
+ node()
+ template = Template(self.meson_build_template())
+ return template.substitute(self.substitutions)
+
+
+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"
+ )
+
+ 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"),
+ )
+ # 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