使用 f2py 和 scikit-build-core 构建时未定义的引用

问题描述 投票:0回答:1

我有一个带有 Fortran 90 扩展的 Python 包。最初,我使用 distutils 和 f2py 来构建扩展,但由于它已被弃用,我改用 scikit-build 与 cmake 和 f2py 结合使用。这是有效的,但最近对某些用户来说开始失败(我怀疑是由于某些安装工具的弃用)。我正在尝试切换到

scikit-build-core
(参见此处),这样可以完全避免使用 setuptools,但我现在看到一个我不太理解的错误。

我已经根据 scikit-build-core 文档上的示例编写了 CMakeLists.txt:

cmake_minimum_required(VERSION 3.17.2...3.29)
project(${SKBUILD_PROJECT_NAME} LANGUAGES C Fortran)

find_package(
  Python
  COMPONENTS Interpreter Development.Module NumPy
  REQUIRED)

set(CMAKE_VERBOSE_MAKEFILE ON)

# 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)

add_library(fortranobject OBJECT "${F2PY_INCLUDE_DIR}/fortranobject.c")
target_link_libraries(fortranobject PUBLIC Python::NumPy)
target_include_directories(fortranobject PUBLIC "${F2PY_INCLUDE_DIR}")
set_property(TARGET fortranobject PROPERTY POSITION_INDEPENDENT_CODE ON)

set(f2py_module_name "calc11")
set(fortran_src_file "${CMAKE_BINARY_DIR}/calc11/src/calc11.f90")
set(generated_module_file ${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_name}${PYTHON_EXTENSION_MODULE_SUFFIX})

# Generate param11.in file in cmake build directory
file(READ ${CMAKE_SOURCE_DIR}/calc11/src/param11.i.in CONTENTS)
file(WRITE ${CMAKE_SOURCE_DIR}/calc11/src/param11.i ${CONTENTS})

# This is the path with all of the fortran code, which gets concatenated into a single file "calc11.f90"
add_subdirectory(calc11)

# Include all the include files
file(GLOB includes ${CMAKE_SOURCE_DIR}"/calc11/src/*.i")
list(PREPEND includes ${generated_module_file})

# Run f2py to generate extension
add_custom_command(
  OUTPUT ${generated_module_file}
  DEPENDS ${includes}
  VERBATIM
  COMMAND "${Python_EXECUTABLE}" -m numpy.f2py
          "${fortran_src_file}" -m ${f2py_module_name} --lower)

python_add_library(${f2py_module_name} MODULE "${fortran_src_file}" WITH_SOABI)
target_link_libraries(${f2py_module_name} PRIVATE fortranobject)

install(TARGETS ${f2py_module_name} DESTINATION ${SKBUILD_PROJECT_NAME})

我的理解是 f2py 需要

fortranobject
库才能正确构建内容,但它之所以存在只是因为它在示例代码中。

当我编译扩展时,我从链接器中收到此错误:

 [5/5] Linking Fortran shared module calc11.cpython-311-x86_64-linux-gnu.so
      FAILED: calc11.cpython-311-x86_64-linux-gnu.so
      : && /usr/bin/gfortran -fPIC -O3 -DNDEBUG -O3   -shared  -o calc11.cpython-311-x86_64-linux-gnu.so CMakeFiles/fortranobject.dir/tmp/pip-build-env-ebv97u47/overlay/lib/python3.11/site-packages/numpy/f2py/src/fortranobject.c.o CMakeFiles/calc11.dir/calc11/src/calc11.f90.o   && :
      /usr/bin/ld: CMakeFiles/fortranobject.dir/tmp/pip-build-env-ebv97u47/overlay/lib/python3.11/site-packages/numpy/f2py/src/fortranobject.c.o: in function `get_elsize':
      fortranobject.c:(.text+0x240): undefined reference to `_npy_f2py_ARRAY_API'
      /usr/bin/ld: CMakeFiles/fortranobject.dir/tmp/pip-build-env-ebv97u47/overlay/lib/python3.11/site-packages/numpy/f2py/src/fortranobject.c.o: relocation R_X86_64_PC32 against undefined hidden symbol `_npy_f2py_ARRAY_API' can not be used when making a shared object
      /usr/bin/ld: final link failed: bad value

即,fortranobject 库中没有“_npy_f2py_ARRAY_API”。

我之前能够使用旧版本的 numpy (1.23) 来编译扩展模块,但是当我导入它时,它仍然给我错误,即 _npy_f2py_ARRAY_API 未定义。

问题似乎来自

target_link_libraries
命令,因为如果我忽略它,它就会构建。但是,在这种情况下编译的模块会出错(显然需要链接到 fortranobject)。

numpy fortran f2py scikit-build
1个回答
0
投票

我能够解决这个问题。问题似乎是原来的

scikit-build
distutils
本身做了很多工作来包含必要的 f2py 库,而我没有包含正确的。

对 f2py 的调用以及添加库并链接它的后续代码应该是这样的:

add_custom_command(
  OUTPUT calc11module.c calc11-f2pywrappers.f calc11-f2pywrappers2.f90
  DEPENDS ${includes}
  VERBATIM
  COMMAND "${Python_EXECUTABLE}" -m numpy.f2py
          "${fortran_src_file}" -m ${f2py_module_name} --lower
  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)

python_add_library(
        ${f2py_module_name}
       MODULE
       "${CMAKE_CURRENT_BINARY_DIR}/calc11-f2pywrappers2.f90"
       "${CMAKE_CURRENT_BINARY_DIR}/calc11-f2pywrappers.f"
       "${CMAKE_CURRENT_BINARY_DIR}/calc11module.c"
       "${fortran_src_file}"
       WITH_SOABI)
target_link_libraries(${f2py_module_name} PRIVATE fortranobject)

“f2pywrapper”文件为Python函数提供必要的API。此链接正确,现在可以运行。

© www.soinside.com 2019 - 2024. All rights reserved.