Использование через cmake#
С точки зрения сложности, cmake находится между make и meson. Кривая
обучения круче, поскольку синтаксис CMake не питонический и ближе к
make с помощью переменных окружения.
Однако компромиссом является повышенная гибкость и поддержка большинства архитектур и компиляторов. Введение в синтаксис выходит за рамки этого документа, но это обширная коллекция CMake ресурсов велико.
Примечание
cmake очень популярен для систем со смешанными языками, однако поддержка для
f2py не является особенно естественным или удобным; и более естественный подход
заключается в рассмотрении Использование через scikit-build
Пошаговое руководство по Фибоначчи (F77)#
Возвращаясь к fib пример из Три способа обертки - начало работы раздел.
C FILE: FIB1.F
SUBROUTINE FIB(A,N)
C
C CALCULATE FIRST N FIBONACCI NUMBERS
C
INTEGER N
REAL*8 A(N)
DO I=1,N
IF (I.EQ.1) THEN
A(I) = 0.0D0
ELSEIF (I.EQ.2) THEN
A(I) = 1.0D0
ELSE
A(I) = A(I-1) + A(I-2)
ENDIF
ENDDO
END
C END FILE FIB1.F
Нам не нужно явно генерировать python -m numpy.f2py fib1.f
вывод, который fib1module.c, что полезно. С этим; мы теперь можем инициализировать CMakeLists.txt файл следующим образом:
cmake_minimum_required(VERSION 3.18) # Needed to avoid requiring embedded Python libs too
project(fibby
VERSION 1.0
DESCRIPTION "FIB module"
LANGUAGES C Fortran
)
# Safety net
if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
message(
FATAL_ERROR
"In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.\n"
)
endif()
# Grab Python, 3.8 or newer
find_package(Python 3.8 REQUIRED
COMPONENTS Interpreter Development.Module NumPy)
# Grab the variables from a local Python installation
# F2PY headers
execute_process(
COMMAND "${Python_EXECUTABLE}"
-c "import numpy.f2py; print(numpy.f2py.get_include())"
OUTPUT_VARIABLE F2PY_INCLUDE_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Print out the discovered paths
include(CMakePrintHelpers)
cmake_print_variables(Python_INCLUDE_DIRS)
cmake_print_variables(F2PY_INCLUDE_DIR)
cmake_print_variables(Python_NumPy_INCLUDE_DIRS)
# Common variables
set(f2py_module_name "fibby")
set(fortran_src_file "${CMAKE_SOURCE_DIR}/fib1.f")
set(f2py_module_c "${f2py_module_name}module.c")
# Generate sources
add_custom_target(
genpyf
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_c}"
)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_c}"
COMMAND ${Python_EXECUTABLE} -m "numpy.f2py"
"${fortran_src_file}"
-m "fibby"
--lower # Important
DEPENDS fib1.f # Fortran source
)
# Set up target
Python_add_library(${CMAKE_PROJECT_NAME} MODULE WITH_SOABI
"${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_c}" # Generated
"${F2PY_INCLUDE_DIR}/fortranobject.c" # From NumPy
"${fortran_src_file}" # Fortran source(s)
)
# Depend on sources
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE Python::NumPy)
add_dependencies(${CMAKE_PROJECT_NAME} genpyf)
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE "${F2PY_INCLUDE_DIR}")
Ключевой элемент CMakeLists.txt файл, определенный выше, заключается в том, что
add_custom_command используется для генерации оболочки C файлы, а затем добавлены как зависимость фактической цели общей библиотеки через
add_custom_target директива, которая предотвращает выполнение команды каждый раз. Кроме того, метод, используемый для получения fortranobject.c файл также может использоваться для получения numpy заголовки на старых cmake версии.
Это затем работает так же, как и другие модули, хотя соглашения об именовании отличаются, и выходная библиотека не автоматически префиксируется с cython информация.
ls .
# CMakeLists.txt fib1.f
cmake -S . -B build
cmake --build build
cd build
python -c "import numpy as np; import fibby; a = np.zeros(9); fibby.fib(a); print (a)"
# [ 0. 1. 1. 2. 3. 5. 8. 13. 21.]
Это особенно полезно, когда уже существует существующий инструментарий и
scikit-build или другие дополнительные python зависимости не рекомендуются.