Compile and import a f2py module, built from the given files.
(source_files, options=[], skip=[], only=[], module_name=None)
| 196 | |
| 197 | @_memoize |
| 198 | def build_module(source_files, options=[], skip=[], only=[], module_name=None): |
| 199 | """ |
| 200 | Compile and import a f2py module, built from the given files. |
| 201 | |
| 202 | """ |
| 203 | |
| 204 | code = f"import sys; sys.path = {sys.path!r}; import numpy.f2py; numpy.f2py.main()" |
| 205 | |
| 206 | d = get_module_dir() |
| 207 | # gh-27045 : Skip if no compilers are found |
| 208 | if not has_fortran_compiler(): |
| 209 | pytest.skip("No Fortran compiler available") |
| 210 | |
| 211 | # Copy files |
| 212 | dst_sources = [] |
| 213 | f2py_sources = [] |
| 214 | for fn in source_files: |
| 215 | if not os.path.isfile(fn): |
| 216 | raise RuntimeError(f"{fn} is not a file") |
| 217 | dst = os.path.join(d, os.path.basename(fn)) |
| 218 | shutil.copyfile(fn, dst) |
| 219 | dst_sources.append(dst) |
| 220 | |
| 221 | base, ext = os.path.splitext(dst) |
| 222 | if ext in (".f90", ".f95", ".f", ".c", ".pyf"): |
| 223 | f2py_sources.append(dst) |
| 224 | |
| 225 | assert f2py_sources |
| 226 | |
| 227 | # Prepare options |
| 228 | if module_name is None: |
| 229 | module_name = get_temp_module_name() |
| 230 | gil_options = [] |
| 231 | if '--freethreading-compatible' not in options and '--no-freethreading-compatible' not in options: |
| 232 | # default to disabling the GIL if unset in options |
| 233 | gil_options = ['--freethreading-compatible'] |
| 234 | f2py_opts = ["-c", "-m", module_name] + options + gil_options + f2py_sources |
| 235 | f2py_opts += ["--backend", "meson"] |
| 236 | if skip: |
| 237 | f2py_opts += ["skip:"] + skip |
| 238 | if only: |
| 239 | f2py_opts += ["only:"] + only |
| 240 | |
| 241 | # Build |
| 242 | cwd = os.getcwd() |
| 243 | try: |
| 244 | os.chdir(d) |
| 245 | cmd = [sys.executable, "-c", code] + f2py_opts |
| 246 | p = subprocess.Popen(cmd, |
| 247 | stdout=subprocess.PIPE, |
| 248 | stderr=subprocess.STDOUT) |
| 249 | out, err = p.communicate() |
| 250 | if p.returncode != 0: |
| 251 | raise RuntimeError(f"Running f2py failed: {cmd[4:]}\n{asunicode(out)}") |
| 252 | finally: |
| 253 | os.chdir(cwd) |
| 254 | |
| 255 | # Partial cleanup |
no test coverage detected
searching dependent graphs…