Thanks to visit codestin.com
Credit goes to github.com

Skip to content

ENH: Meson build system support for F2PY's f2py -c command #22225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 132 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
a5dfd68
ENH: Start refactoring f2py front-end
HaoZeke Oct 5, 2021
1eacfb0
ENH: Start using logging
HaoZeke Oct 5, 2021
173a7bb
ENH: Add more options for the new front-end
HaoZeke Oct 5, 2021
52762a9
ENH: Half the f2py options
HaoZeke Oct 5, 2021
c0689cb
ENH: Switch to using f2pyarg
HaoZeke Oct 18, 2021
44bec87
ENH: Add f2py frontend stuff
HaoZeke Oct 18, 2021
81b14f4
FIX: f2pyarg --build-dir create directory if not present
NamamiShanker Jun 30, 2022
7c68149
MAINT: Move f2pyarg helpers to service
NamamiShanker Jun 30, 2022
9ab806a
FIX: Fix incorrect imports in f2pyarg service
NamamiShanker Jun 30, 2022
c70272c
MAINT: f2py check if input f2cmap file exists
NamamiShanker Jun 30, 2022
9fde953
MAINT: Fix --wrap-functions docs
NamamiShanker Jun 30, 2022
4c4b99a
MAINT: f2pyarg Remove unnecessary flags
NamamiShanker Jul 2, 2022
bbb44a7
MAINT: f2pyarg remove unnecessary flags
NamamiShanker Jul 2, 2022
d26bd6a
MAINT: f2pyarg fix default values
NamamiShanker Jul 2, 2022
9ce2140
FIX: f2pyarg transfer -h flag to generate_wrappers parser
NamamiShanker Jul 2, 2022
bcf7902
ENH: f2pyarg add file segregation method
NamamiShanker Jul 2, 2022
568b94d
ENH: Create temp dir for null builddir value
NamamiShanker Jul 2, 2022
b3d8a2b
ENH: Chop callcrackfortran and move it to service. Add other helpers.
NamamiShanker Jul 2, 2022
4180fca
ENH: Initial f2pyarg main arg process function
NamamiShanker Jul 2, 2022
a0eab32
FIX: fix imports
NamamiShanker Jul 3, 2022
528dc4f
FIX: Set default verbosity to true like f2py2e
NamamiShanker Jul 3, 2022
d2a72b1
MAINT: Remove unneccessary imports
NamamiShanker Jul 3, 2022
475f4df
ENH: Handle overwrite-signature flag
NamamiShanker Jul 3, 2022
aa3d300
ENH: update auxfuncs
NamamiShanker Jul 4, 2022
885c772
ENH: Segregate pyf files
NamamiShanker Jul 4, 2022
f39eb6d
MAINT: Refactoring
NamamiShanker Jul 4, 2022
1df8ee2
MAINT: Rename _parse_postlist to _check_postlist
NamamiShanker Jul 4, 2022
15be187
Revert "ENH: update auxfuncs"
NamamiShanker Jul 5, 2022
e13faa1
FIX: Accept array of debug options rather that boolean flag
NamamiShanker Jul 5, 2022
28e5beb
FIX: Default module name and default build directories
NamamiShanker Jul 5, 2022
810aad7
MAINT: Fix typo and send pyf files to generate_files
NamamiShanker Jul 5, 2022
bc8dfa9
ENH: Send all required options to rules file
NamamiShanker Jul 5, 2022
fc68223
MAINT: Refactoring service
NamamiShanker Jul 5, 2022
be8a4b0
MAINT: Refactor for -c flag
NamamiShanker Jul 8, 2022
d7ad3ec
FIX: Change -c flag default val
NamamiShanker Jul 8, 2022
7409f5a
ENH: Remove alternative macro flags for easier handling
NamamiShanker Jul 8, 2022
da01606
ENH: Add action class to process macros
NamamiShanker Jul 8, 2022
c2f600f
FIX: BoolAction string has no contains method error
NamamiShanker Jul 8, 2022
fd58788
FIX: NPDLinkHelper setattr failure
NamamiShanker Jul 8, 2022
526d374
ENH: Add initial -c flag handling
NamamiShanker Jul 8, 2022
70352a3
ENH: Add get_f2py_modulename function from np.distutils
NamamiShanker Jul 8, 2022
c8fc749
FIX: _check_postlist verbosity error
NamamiShanker Jul 8, 2022
15b7baa
FIX: Change module_name to module
NamamiShanker Jul 8, 2022
dea01ca
FIX: Parse skip and only arguments
NamamiShanker Jul 8, 2022
392101b
FIX: Segregate and return path of input files
NamamiShanker Jul 8, 2022
50e2c85
FIX: data type of f77flags and f90flags
NamamiShanker Jul 11, 2022
9f3efd1
FIX: Return signature file
NamamiShanker Jul 11, 2022
e902559
MAINT: Refactor file segregation
NamamiShanker Jul 11, 2022
bb41e54
ENH: Support for -include<header> flag
NamamiShanker Jul 11, 2022
39ef205
MAINT: Refactor wrapper generation settings
NamamiShanker Jul 11, 2022
5d9f607
FIX: Import f2py2e rather than f2py for run_main
NamamiShanker Jul 11, 2022
9ad8f81
ENH: Generate comp flagsfrom parser namespace
NamamiShanker Jul 11, 2022
02e9ecd
ENH: Add f2pyarg distutils compilation
NamamiShanker Jul 11, 2022
19b3948
FIX: link_resource default value
NamamiShanker Jul 11, 2022
f101211
ENH: Add util file for f2py
NamamiShanker Jul 11, 2022
fc2a708
MAINT: Minor refactoring
NamamiShanker Jul 11, 2022
2e38e83
FIX: Import f2py2e instead of f2py
NamamiShanker Jul 12, 2022
bbad3ea
MAINT: Remove unused imports
NamamiShanker Jul 12, 2022
80192f9
ENH: Use context manager for build_dir management
NamamiShanker Jul 12, 2022
d0f7d3e
MAINT: Remove whitespaces
NamamiShanker Jul 12, 2022
68b79eb
FIX: Return after generating signature
NamamiShanker Jul 12, 2022
691059e
FIX: Return string path of files
NamamiShanker Jul 12, 2022
21cfaf1
FIX: Remove sneaky breakpoint
NamamiShanker Jul 12, 2022
30748db
MAINT: Remove unused build_dir function
NamamiShanker Jul 12, 2022
5539245
FIX: Processing macros
NamamiShanker Jul 12, 2022
8226050
FIX: f2cmap flag picking up positional args
NamamiShanker Jul 12, 2022
4f9c847
FIX: Print f2py version
NamamiShanker Jul 12, 2022
f4ab7fa
TST: Add f2pyarg modules to public api list
NamamiShanker Jul 13, 2022
7782efe
ENH: Add f2cmap support to f2pyarg compilation
NamamiShanker Jul 13, 2022
51290b1
ENH: Add typing support
NamamiShanker Jul 24, 2022
69d3a2f
ENH: Add typing support to f2pyarg
NamamiShanker Jul 24, 2022
1c8d67e
FIX: Typing in f2py service file
NamamiShanker Jul 24, 2022
8cec862
MAINT: Remove unnecessary imports
NamamiShanker Jul 24, 2022
1b2d883
FIX: Add pyf.src file support to f2pyarg
NamamiShanker Jul 24, 2022
8217138
FIX: Remove os.path dependency from f2pyarg
NamamiShanker Jul 24, 2022
b3823b1
FIX: Remove os.path dependency from f2py service
NamamiShanker Jul 24, 2022
499c45c
FIX: Replace os.path with pathlib.Path
NamamiShanker Jul 24, 2022
f20254e
FIX: Typing
NamamiShanker Jul 24, 2022
68789c5
MAINT: Use boolean values instead of integers
NamamiShanker Jul 24, 2022
91b77bf
MAINT: Refactorings
NamamiShanker Jul 24, 2022
7762341
MAINT: Remove unnecessary comments
NamamiShanker Jul 24, 2022
6bd3e6c
FIX: set_dependecies_dist potential bug
NamamiShanker Jul 24, 2022
5fd5123
MAINT: Rename regex variables as module constants
NamamiShanker Jul 24, 2022
911fd6a
MAINT: Replace os.path with pathlib.Path
NamamiShanker Jul 24, 2022
dac9dd4
MAINT: Typing and pathlib related refactoring
NamamiShanker Jul 24, 2022
b891188
FIX: Passing rem to f2pyflags_dist
NamamiShanker Jul 24, 2022
47a9426
FIX: Always convert f2cmap_file to Path type
NamamiShanker Jul 24, 2022
5772ec6
MAINT: Apply changes from code review
NamamiShanker Jul 24, 2022
0455847
MAINT: No need to use try..finally
NamamiShanker Jul 24, 2022
e1f722f
FIX: Return full path string
NamamiShanker Jul 24, 2022
302c77c
FIX: Print name of PosiPath type variable
NamamiShanker Jul 24, 2022
f105eec
MAINT: Refactorings from code review
NamamiShanker Jul 24, 2022
1cc1ab9
MAINT: Refactorings from code review
NamamiShanker Jul 24, 2022
116315e
FIX: Typing errors
NamamiShanker Jul 24, 2022
4b55a17
FIX: Replace builtin types with typing
NamamiShanker Jul 24, 2022
232decf
MAINT: Add docstring to explain open_build_dir
NamamiShanker Jul 24, 2022
257b443
ENH: Add temporary comments
NamamiShanker Jul 24, 2022
d8061f4
ENH: Use builtin types in place of typing
NamamiShanker Jul 25, 2022
3aa40b7
ENH: Return c wrapper path
NamamiShanker Aug 5, 2022
ac164c7
ENH: Add --backend flag for meson integration
NamamiShanker Aug 7, 2022
58fb9c3
BUG: Seperate paths by colon
NamamiShanker Aug 7, 2022
e4c5d0b
BUG: Add default values and pass paths as strings
NamamiShanker Aug 7, 2022
5f599aa
ENH: Add initial meson plugin
NamamiShanker Aug 7, 2022
e9fe1ce
ENH: Use meson backend in f2pyarg
NamamiShanker Aug 7, 2022
379bb56
MAINT: Sort by alphabetical order
NamamiShanker Aug 7, 2022
f1d93c0
MAINT: Fix typo
NamamiShanker Aug 12, 2022
8c0858b
ENH: Add custom string flags parsing
NamamiShanker Aug 12, 2022
5b99e87
FIX: Flag nargs
NamamiShanker Aug 18, 2022
af364d0
MAINT: Correct docstring
NamamiShanker Aug 18, 2022
2154c47
MAINT:Refactor variable names according to f2pyarg
NamamiShanker Aug 18, 2022
2803ac5
MAINT: Fix docstring
NamamiShanker Aug 18, 2022
5a2706f
FIX: Add flags
NamamiShanker Aug 18, 2022
198895c
ENH: Update f2pyarg with full meson backend params
NamamiShanker Aug 20, 2022
6f8ccbb
ENH: Basic prototype meson backend
NamamiShanker Aug 20, 2022
28414fa
BUG: f2pyarg bugfixes
NamamiShanker Aug 24, 2022
66fd50a
MAINT: Return Path object of tempdir
NamamiShanker Aug 24, 2022
dd08d47
ENH: Add F2PY backend directory to install config
NamamiShanker Aug 24, 2022
9ab0c9d
BUG: Generate using pyf files
NamamiShanker Aug 25, 2022
706443c
ENH: Accept f77, f90 and object files seperately
NamamiShanker Aug 25, 2022
4a114ce
ENH: Add f2py backends to public API list
NamamiShanker Aug 25, 2022
26cc090
BUG: Lower C wrapper defs by default for less buggy imports
NamamiShanker Aug 26, 2022
ee41f1e
BUG: Read module name from pyf file without -c
NamamiShanker Aug 26, 2022
76ab74b
BUG: Fix enum action for switching backends
NamamiShanker Aug 26, 2022
bfd5c86
Revert "BUG: Read module name from pyf file without -c"
NamamiShanker Aug 29, 2022
24d7087
BUG: Change default value of lower flag
NamamiShanker Aug 31, 2022
46c466f
BUG: Change default module name
NamamiShanker Aug 31, 2022
29c31ee
MAINT: Set Default empty gen False
NamamiShanker Aug 31, 2022
64fdd3e
BUG: Return list of wrappers from generate_files
NamamiShanker Aug 31, 2022
5888fbf
BUG: Get module name from postlist
NamamiShanker Aug 31, 2022
5664a98
BUG: Shift files to the end of sys.argv
NamamiShanker Sep 7, 2022
a1b8219
BUG: Import annotations for python3.8
NamamiShanker Sep 7, 2022
cf21444
BUG: f2pyarg sort args fix
NamamiShanker Sep 7, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions numpy/distutils/command/build_src.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,8 +539,8 @@ def f2py_sources(self, sources, extension):
if (self.force or newer_group(depends, target_file, 'newer')) \
and not skip_f2py:
log.info("f2py: %s" % (source))
import numpy.f2py
numpy.f2py.run_main(f2py_options
from numpy.f2py import f2py2e
f2py2e.run_main(f2py_options
+ ['--build-dir', target_dir, source])
else:
log.debug(" skipping '%s' f2py interface (up-to-date)" % (source))
Expand All @@ -558,8 +558,8 @@ def f2py_sources(self, sources, extension):
and not skip_f2py:
log.info("f2py:> %s" % (target_file))
self.mkpath(target_dir)
import numpy.f2py
numpy.f2py.run_main(f2py_options + ['--lower',
from numpy.f2py import f2py2e
f2py2e.run_main(f2py_options + ['--lower',
'--build-dir', target_dir]+\
['-m', ext_name]+f_sources)
else:
Expand Down
9 changes: 3 additions & 6 deletions numpy/f2py/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@
"""Fortran to Python Interface Generator.

"""
__all__ = ['run_main', 'compile', 'get_include']
__all__ = ['main', 'compile', 'get_include']

import sys
import subprocess
import os

from . import f2py2e
from . import diagnose

run_main = f2py2e.run_main
main = f2py2e.main
from numpy.f2py.f2pyarg import main


def compile(source,
Expand Down Expand Up @@ -102,7 +99,7 @@ def compile(source,

c = [sys.executable,
'-c',
'import numpy.f2py as f2py2e;f2py2e.main()'] + args
'from numpy.f2py import main;main()'] + args
try:
cp = subprocess.run(c, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
Expand Down
2 changes: 1 addition & 1 deletion numpy/f2py/__main__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# See:
# https://web.archive.org/web/20140822061353/http://cens.ioc.ee/projects/f2py2e
from numpy.f2py.f2py2e import main
from numpy.f2py.f2pyarg import main

main()
6 changes: 6 additions & 0 deletions numpy/f2py/backends/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from .backend import Backend
from .meson_backend import MesonBackend

backends = {
'meson': MesonBackend
}
110 changes: 110 additions & 0 deletions numpy/f2py/backends/backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
from __future__ import annotations

from pathlib import Path
from abc import ABC, abstractmethod

import numpy
import numpy.f2py as f2py

class Backend(ABC):
"""
Superclass for backend compilation plugins to extend.

"""

def __init__(self, module_name, fortran_compiler: str, c_compiler: str,
f77exec: Path, f90exec: Path, f77_flags: list[str],
f90_flags: list[str], include_paths: list[Path],
include_dirs: list[Path], external_resources: list[str],
linker_libpath: list[Path], linker_libname: list[str],
define_macros: list[tuple[str, str]], undef_macros: list[str],
debug: bool, opt_flags: list[str], arch_flags: list[str],
no_opt: bool, no_arch: bool) -> None:
"""
The class is initialized with f2py compile options.
The parameters are mappings of f2py compilation flags.

Parameters
----------
module_name : str
The name of the module to be compiled. (-m)
fortran_compiler : str
Name of the Fortran compiler to use. (--fcompiler)
c_compiler : str
Name of the C compiler to use. (--ccompiler)
f77exec : Pathlike
Path to the fortran compiler for Fortran 77 files (--f77exec)
f90exec : Pathlike
Path to the fortran compiler for Fortran 90 and above files (--f90exec)
f77_flags : list
List of flags to pass to the fortran compiler for Fortran 77 files (--f77flags)
f90_flags : list
List of flags to pass to the fortran compiler for Fortran 90 and above files (--f90flags)
include_paths : list
Search include files from given directories (--include-paths)
include_dirs : list
Append directory <dir> to the list of directories searched for include files. (-I<dir>)
external_resources : list
Link the extension module with <resource> (--link-<resource>)
linker_libname : list
Use the library when linking. (-l<libname>)
define_macros : list
Define <macro> to <value> if present else define <macro> to true (-D)
undef_macros : list
Undefine <macro> (-U)
linker_libpath : list
Add directory to the list of directories to be searched for `-l`. (-L)
opt_flags : list
Optimization flags to pass to the compiler. (--opt)
arch_flags : list
Architectire specific flags to pass to the compiler (--arch)
no_opt : bool
Disable optimization. (--no-opt)
no_arch : bool
Disable architecture specific optimizations. (--no-arch)
debug : bool
Enable debugging. (--debug)

"""
self.module_name = module_name
self.fortran_compiler = fortran_compiler
self.c_compiler = c_compiler
self.f77exec = f77exec
self.f90exec = f90exec
self.f77_flags = f77_flags
self.f90_flags = f90_flags
self.include_paths = include_paths
self.include_dirs = include_dirs
self.external_resources = external_resources
self.linker_libpath = linker_libpath
self.linker_libname = linker_libname
self.define_macros = define_macros
self.undef_macros = undef_macros
self.debug = debug
self.opt_flags = opt_flags
self.arch_flags = arch_flags
self.no_opt = no_opt
self.no_arch = no_arch

def numpy_install_path(self) -> Path:
"""
Returns the install path for numpy.
"""
return Path(numpy.__file__).parent

def numpy_get_include(self) -> Path:
"""
Returns the include paths for numpy.
"""
return Path(numpy.get_include())

def f2py_get_include(self) -> Path:
"""
Returns the include paths for f2py.
"""
return Path(f2py.get_include())

@abstractmethod
def compile(self, fortran_sources: Path, c_wrapper: Path, build_dir: Path) -> None:
"""Compile the wrapper."""
pass
183 changes: 183 additions & 0 deletions numpy/f2py/backends/meson_backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
from __future__ import annotations

import os
import errno
import shutil
import subprocess
from pathlib import Path

from .backend import Backend
from string import Template

class MesonTemplate:
"""Template meson build file generation class."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's tabs here instead of spaces. @NamamiShanker can you please check your editor settings and ensure tabs are always converted to spaces?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure @rgommers. I corrected this file and the others.

def __init__(self, module_name: str, numpy_install_path, numpy_get_include: Path, f2py_get_include: Path, wrappers: list[Path], fortran_sources: list[Path], dependencies: list[str], include_path: list[Path], optimization_flags: list[str], architecture_flags: list[str], f77_flags: list[str], f90_flags: list[str], linker_libpath: list[Path], linker_libname: list[str], define_macros: list[tuple[str, str]], undef_macros: list[str]):
self.module_name = module_name
self.numpy_install_path = numpy_install_path
self.build_template_path = numpy_install_path / "f2py" / "backends" / "src" / "meson.build.src"
self.sources = fortran_sources
self.numpy_get_include = numpy_get_include
self.f2py_get_include = f2py_get_include
self.wrappers = wrappers
self.dependencies = dependencies
self.include_directories = include_path
self.substitutions = {}
self.optimization_flags = optimization_flags
self.architecture_flags = architecture_flags
self.fortran_flags = f77_flags + f90_flags
self.linker_libpath = linker_libpath
self.linker_libname = linker_libname
self.define_macros = define_macros
self.undef_macros = undef_macros
self.pipeline = [self.initialize_template,
self.global_flags_substitution,
self.sources_substitution,
self.dependencies_substitution,
self.include_directories_subtitution,
self.linker_substitution,
self.macros_substitution]

@property
def meson_build_template(self) -> str:
if(not self.build_template_path.is_file()):
raise FileNotFoundError(errno.ENOENT, f"Meson build template {self.build_template_path.absolute()} does not exist.")
return self.build_template_path.read_text()

def initialize_template(self) -> None:
"""Initialize with module name and external NumPy and F2PY C libraries."""
self.substitutions['modulename'] = self.module_name
self.substitutions['numpy_get_include'] = self.numpy_get_include.absolute()
self.substitutions['f2py_get_include'] = self.f2py_get_include.absolute()
Comment on lines +49 to +50
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these necessary? The documentation includes the option to get these dynamically from meson...


def sources_substitution(self) -> None:
self.substitutions["source_list"] = ",".join(["\'"+str(source.absolute())+"\'" for source in self.sources])
self.substitutions["wrappers"] = ",".join(["\'"+str(wrapper.absolute())+"\'" for wrapper in self.wrappers])

def dependencies_substitution(self) -> None:
self.substitutions["dependencies_list"] = ", ".join([f"dependency('{dependecy}')" for dependecy in self.dependencies])

def include_directories_subtitution(self) -> None:
self.substitutions["include_directories_list"] = ", ".join([f"include_directories('{include_directory}')" for include_directory in self.include_directories])

def global_flags_substitution(self) -> None:
fortran_compiler_flags = self.fortran_flags + self.optimization_flags + self.architecture_flags
c_compiler_flags = self.optimization_flags + self.architecture_flags
self.substitutions["fortran_global_args"] = fortran_compiler_flags
self.substitutions["c_global_args"] = c_compiler_flags
Comment on lines +62 to +66
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Global flags are generally a bad idea, especially since a lot of these might be used as subprojects, it makes more sense to populate the _project variants.


def macros_substitution(self) -> None:
self.substitutions["macros"] = ""
if self.define_macros:
self.substitutions["macros"] = ",".join(f"\'-D{macro[0]}={macro[1]}\'" if macro[1] else f"-D{macro[0]}" for macro in self.define_macros)
if self.undef_macros:
self.substitutions["macros"] += "," + ",".join(f"\'-U{macro}\'" for macro in self.undef_macros)
Comment on lines +68 to +73
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These don't pass -D flags to the underlying preprocessor, that would have to be via Dc_args=-D{macro[0]}={macro[1]}... (e.g. seen here)

Similar issue with unsetting the defines.


def linker_substitution(self) -> None:
self.substitutions["linker_args"] = ""
if self.linker_libpath:
linker_libpath_subs = ",".join(f"-L{libpath}" for libpath in self.linker_libpath)
self.substitutions["linker_args"] += linker_libpath_subs
if self.linker_libname:
linker_libname_subs = ",".join(f"-l{libname}" for libname in self.linker_libname)
self.substitutions["linker_args"] += f",{linker_libname_subs}"
Comment on lines +75 to +82
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as above.


def generate_meson_build(self) -> str:
for node in self.pipeline:
node()
template = Template(self.meson_build_template)
return template.substitute(self.substitutions)


class MesonBackend(Backend):

def __init__(self, module_name: str = 'untitled', fortran_compiler: str = None, c_compiler: str = None, f77exec: Path = None, f90exec: Path = None, f77_flags: list[str] = None, f90_flags: list[str] = None, include_paths: list[Path] = None, include_dirs: list[Path] = None, external_resources: list[str] = None, linker_libpath: list[Path] = None, linker_libname: list[str] = None, define_macros: list[tuple[str, str]] = None, undef_macros: list[str] = None, debug: bool = False, opt_flags: list[str] = None, arch_flags: list[str] = None, no_opt: bool = False, no_arch: bool = False) -> None:
self.meson_build_dir = "builddir"
if f77_flags is None:
f77_flags = []
if include_paths is None:
include_paths = []
if include_dirs is None:
include_dirs = []
if external_resources is None:
external_resources = []
if linker_libpath is None:
linker_libpath = []
if linker_libname is None:
linker_libname = []
if define_macros is None:
define_macros = []
if undef_macros is None:
undef_macros = []
if f77_flags is None:
f77_flags = []
if f90_flags is None:
f90_flags = []
if opt_flags is None:
opt_flags = []
if arch_flags is None:
arch_flags = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These flags don't quite fit anymore (the difference between F77 and F90 is not needed, nor are the exact paths to the compiler; the --opt, --arch etc. are specified in a very non-standard way, Meson has a better way to do things like debug flags). Is there a plan to clean this up? Maybe they should be kept unchanged for now, and then when numpy.distutils is gone they can be updated?

super().__init__(module_name, fortran_compiler, c_compiler, f77exec, f90exec, f77_flags, f90_flags, include_paths, include_dirs, external_resources, linker_libpath, linker_libname, define_macros, undef_macros, debug, opt_flags, arch_flags, no_opt, no_arch)

self.wrappers: list[Path] = []
self.fortran_sources: list[Path] = []
self.template = Template(self.fortran_sources)

def _get_optimization_level(self):
if self.no_arch and not self.no_opt :
return 2
elif self.no_opt :
return 0
return 3

def _set_environment_variables(self) -> None:
if self.fortran_compiler:
os.putenv("FC", self.fortran_compiler)
elif self.f77exec:
os.putenv("FC", self.f77exec)
elif self.f90exec:
os.putenv("FC", self.f90exec)
if self.c_compiler:
os.putenv("CC", self.c_compiler)

def _move_exec_to_root(self, build_dir: Path):
walk_dir = build_dir / self.meson_build_dir
path_objects = walk_dir.glob(f"{self.module_name}*.so")
for path_object in path_objects:
shutil.move(path_object, Path.cwd())

def _get_build_command(self):
return ["meson", "setup", self.meson_build_dir, "-Ddebug=true" if self.debug else "-Ddebug=false", f"-Doptimization={str(self._get_optimization_level())}"]

def load_wrapper(self, wrappers: list[Path]) -> None:
self.wrappers = wrappers

def load_sources(self, fortran_sources: list[Path]) -> None:
for fortran_source in fortran_sources:
fortran_source = Path(fortran_source)
if not fortran_source.is_file():
raise FileNotFoundError(errno.ENOENT, f"{fortran_source.absolute()} does not exist.")
self.fortran_sources.append(fortran_source)

def write_meson_build(self, build_dir: Path) -> None:
"""Writes the meson build file at specified location"""
meson_template = MesonTemplate(self.module_name, super().numpy_install_path(), self.numpy_get_include(), self.f2py_get_include(), self.wrappers, self.fortran_sources, self.external_resources, self.include_paths+self.include_dirs, optimization_flags=self.opt_flags, architecture_flags=self.arch_flags, f77_flags=self.f77_flags, f90_flags=self.f90_flags, linker_libpath=self.linker_libpath, linker_libname=self.linker_libname, define_macros=self.define_macros, undef_macros=self.undef_macros)
src = meson_template.generate_meson_build()
meson_build_file = build_dir / "meson.build"
meson_build_file.write_text(src)
return meson_build_file

def run_meson(self, build_dir: Path):
self._set_environment_variables()
completed_process = subprocess.run(self._get_build_command(), cwd=build_dir)
if(completed_process.returncode != 0):
raise subprocess.CalledProcessError(completed_process.returncode, completed_process.args)
completed_process = subprocess.run(["meson", "compile", "-C", self.meson_build_dir], cwd=build_dir)
if(completed_process.returncode != 0):
raise subprocess.CalledProcessError(completed_process.returncode, completed_process.args)

def compile(self, f77_sources: list[Path], f90_sources:list[Path], object_files: list[Path], wrappers: list[Path], build_dir: Path) -> None:
self.load_wrapper(wrappers)
self.load_sources(f77_sources + f90_sources + object_files)
self.write_meson_build(build_dir)
self.run_meson(build_dir)
self._move_exec_to_root(build_dir)
22 changes: 22 additions & 0 deletions numpy/f2py/backends/src/meson.build.src
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
project('${modulename}', 'c',
version : '0.1',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want to set the minimum meson version here, and it should be very recent; lots of Python bugs were fixed recently. I recommend the most recent release, 0.63.2, and bumping it up to 0.63.3/0.64.0 when those become available.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected it.

default_options : ['warning_level=2'])

add_languages('fortran')

add_global_arguments(${c_global_args}, language: 'c')
add_global_arguments(${fortran_global_args}, language: 'fortran')

py_mod = import('python')
py3 = py_mod.find_installation('python3')
py3_dep = py3.dependency()
message(py3.path())
message(py3.get_install_dir())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have pure: false as argument.


incdir_numpy = '${numpy_get_include}'

incdir_f2py = '${f2py_get_include}'

inc_np = include_directories(incdir_numpy, incdir_f2py)

py3.extension_module('${modulename}', ${wrappers}, ${source_list}, incdir_f2py+'/fortranobject.c', include_directories: [inc_np, ${include_directories_list}], dependencies : [py3_dep, ${dependencies_list}], link_args : '${linker_args}', c_args : [${macros}], install : true)
Loading