-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathFindF2PY.cmake
More file actions
174 lines (154 loc) · 6.89 KB
/
FindF2PY.cmake
File metadata and controls
174 lines (154 loc) · 6.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# MAT This code is based, loosely, on the FindF2PY.cmake file from scikit
#.rst:
#
# The purpose of the F2PY –Fortran to Python interface generator– project is to provide a
# connection between Python and Fortran languages.
#
# F2PY is a Python package (with a command line tool f2py and a module f2py2e) that facilitates
# creating/building Python C/API extension modules that make it possible to call Fortran 77/90/95
# external subroutines and Fortran 90/95 module subroutines as well as C functions; to access Fortran
# 77 COMMON blocks and Fortran 90/95 module data, including allocatable arrays from Python.
#
# For more information on the F2PY project, see http://www.f2py.com/.
#
# The following variables are defined:
#
# ::
#
# F2PY_EXECUTABLE - absolute path to the F2PY executable
#
# ::
#
# F2PY_VERSION_STRING - the version of F2PY found
# F2PY_VERSION_MAJOR - the F2PY major version
# F2PY_VERSION_MINOR - the F2PY minor version
# F2PY_VERSION_PATCH - the F2PY patch version
#
#
# .. note::
#
# By default, the module finds the F2PY program associated with the installed NumPy package.
#
# Path to the f2py executable
## We might have an odd circumstance where there are a couple f2py around. As such,
## we need to find the one that matches the Python_EXECUTABLE. This is a bit of a
## hack, but it should work for most cases.
## Find the directory where the Python_EXECUTABLE is located
message(DEBUG "[F2PY]: Searching for f2py executable associated with Python_EXECUTABLE: ${Python_EXECUTABLE}")
get_filename_component(Python_EXECUTABLE_DIR ${Python_EXECUTABLE} DIRECTORY)
message(DEBUG "[F2PY]: Python executable directory: ${Python_EXECUTABLE_DIR}")
# In Spack environments, f2py lives in the py-numpy package's bin dir, which is
# separate from the Python interpreter's bin dir. Ask Python/numpy directly for
# the path to f2py so we always get the one matching the active numpy.
execute_process(
COMMAND "${Python_EXECUTABLE}" -c "import numpy.f2py; import os; print(os.path.dirname(numpy.f2py.__file__))"
OUTPUT_VARIABLE _numpy_f2py_dir
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (_numpy_f2py_dir)
# numpy.f2py package dir is e.g. .../lib/pythonX.Y/site-packages/numpy/f2py
# Walking up 5 levels reaches the package prefix; bin/ lives alongside lib/.
# Layout: <prefix>/bin/f2py
# lib/pythonX.Y/site-packages/numpy/f2py <- _numpy_f2py_dir
get_filename_component(_numpy_bin_dir "${_numpy_f2py_dir}/../../../../.." ABSOLUTE)
set(_numpy_bin_dir "${_numpy_bin_dir}/bin")
message(DEBUG "[F2PY]: numpy f2py package dir: ${_numpy_f2py_dir}")
message(DEBUG "[F2PY]: numpy-derived bin hint: ${_numpy_bin_dir}")
endif ()
find_program(F2PY_EXECUTABLE
NAMES "f2py${Python_VERSION_MAJOR}"
"f2py${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}"
"f2py-${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}"
"f2py"
PATHS ${Python_EXECUTABLE_DIR}
${_numpy_bin_dir}
HINTS ${Python_EXECUTABLE_DIR}
${_numpy_bin_dir}
NO_DEFAULT_PATH
)
# If not found in the preferred locations, fall back to a normal PATH search.
# This handles non-Spack environments where f2py may be elsewhere on PATH.
if (NOT F2PY_EXECUTABLE)
find_program(F2PY_EXECUTABLE
NAMES "f2py${Python_VERSION_MAJOR}"
"f2py${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}"
"f2py-${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}"
"f2py"
)
endif ()
message(DEBUG "[F2PY]: Found f2py executable: ${F2PY_EXECUTABLE}")
# Now as a sanity check, we need to make sure that the f2py executable is
# actually the one that is associated with the Python_EXECUTABLE
get_filename_component(F2PY_EXECUTABLE_DIR ${F2PY_EXECUTABLE} DIRECTORY)
message(DEBUG "[F2PY]: f2py executable directory: ${F2PY_EXECUTABLE_DIR}")
# Now we issue a WARNING. We can't do more than that because of things like Spack
# where f2py will be in a different location than python.
if (NOT "${F2PY_EXECUTABLE_DIR}" STREQUAL "${Python_EXECUTABLE_DIR}")
message(WARNING
"[F2PY]: The f2py executable [${F2PY_EXECUTABLE}] found is not the one associated with the Python_EXECUTABLE [${Python_EXECUTABLE}].\n"
"Please check your Python environment if this is not expected (for example, not a Spack install) or build with -DUSE_F2PY=OFF.")
endif ()
if(F2PY_EXECUTABLE)
# extract the version string
execute_process(COMMAND "${F2PY_EXECUTABLE}" -v
OUTPUT_VARIABLE F2PY_VERSION_STRING
OUTPUT_STRIP_TRAILING_WHITESPACE)
if("${F2PY_VERSION_STRING}" MATCHES "^([0-9]+)(.([0-9+]))?(.([0-9+]))?$")
set(F2PY_VERSION_MAJOR "${CMAKE_MATCH_1}")
set(F2PY_VERSION_MINOR "${CMAKE_MATCH_3}")
set(F2PY_VERSION_PATCH "${CMAKE_MATCH_5}")
endif()
# Testing has shown that f2py with Python 3.12+ needs to set
# a new CMake policy, CMP0132, because f2py uses Meson in the
# instead of distutils.
# See https://github.com/mesonbuild/meson/issues/13882
if (Python_VERSION_MINOR GREATER_EQUAL 12)
message(STATUS "[F2PY]: Setting CMP0132 policy to NEW")
cmake_policy(SET CMP0132 NEW)
endif ()
# Get the compiler-id and map it to compiler vendor as used by f2py.
# Currently, we only check for GNU, but this can easily be extended.
# Cache the result, so that we only need to check once.
if(NOT F2PY_FCOMPILER)
if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
set(_fcompiler "gnu95")
else(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
set(_fcompiler "gnu")
endif(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
elseif(CMAKE_Fortran_COMPILER_ID MATCHES "Intel")
set(_fcompiler "intelem")
elseif(CMAKE_Fortran_COMPILER_ID MATCHES "NVHPC")
set(_fcompiler "nv")
endif()
set(F2PY_FCOMPILER ${_fcompiler} CACHE STRING
"F2PY: Fortran compiler type by vendor" FORCE)
message(DEBUG "[F2PY]: Fortran compiler type: ${F2PY3_FCOMPILER}")
# Finding the Fortran compiler is only necessary if using distutils.
# For Meson, f2py3 will find the compiler itself. We use meson
# if Python3_VERSION is 3.12 or greater.
if(NOT F2PY_FCOMPILER AND Python_VERSION_MINOR LESS 12)
message(FATAL_ERROR "[F2PY]: Could not determine Fortran compiler type. ")
endif(NOT F2PY_FCOMPILER AND Python_VERSION_MINOR LESS 12)
endif(NOT F2PY_FCOMPILER)
# Now we need to test if we can actually use f2py and what its suffix is
if (NOT F2PY_SUFFIX)
include(try_f2py_compile)
try_f2py_compile(
${CMAKE_CURRENT_LIST_DIR}/test.F90
DETECT_F2PY_SUFFIX
)
endif ()
endif ()
# handle the QUIET and REQUIRED arguments and set F2PY_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(F2PY
REQUIRED_VARS F2PY_EXECUTABLE F2PY_SUFFIX
VERSION_VAR F2PY_VERSION_STRING
)
mark_as_advanced(F2PY_EXECUTABLE F2PY_SUFFIX)
if (F2PY_FOUND)
include(UseF2Py)
endif ()