6

我正在尝试使用 f2py 将我的 python 程序与我的 Fortran 模块接口。

我在Win7平台上。

我使用最新的 Anaconda 64 (1.7) 作为 Python+NumPy 堆栈。

我的 Fortran 编译器是最新的 Intel Fortran 编译器 64(版本 14.0.0.103 Build 20130728)。

我在执行时遇到了许多问题f2py -c -m PyModule FortranModule.f90 --fcompiler=intelvem

最后一个,我似乎无法解决的是,看起来 f2py/distutils 传递给编译器的标志序列与 ifort 期望的不匹配。

调用 ifort 时,我收到一系列有关未知选项的警告消息。

ifort: command line warning #10006: ignoring unknown option '/LC:\Anaconda\libs'
ifort: command line warning #10006: ignoring unknown option'/LC:\Anaconda\PCbuild\amd64'
ifort: command line warning #10006: ignoring unknown option '/lpython27'

我怀疑这与我最后从链接器得到的错误有关

error LNK2019: unresolved external symbol __imp_PyImport_ImportModule referenced in function _import_array
error LNK2019... and so forth (there are about 30-40 lines like that, with different python modules missing)

它以一个简单的结尾

fatal error LNK1120: 42 unresolved externals

我的猜测是,这是因为选项序列中缺少 /link 标志。因此,/l /L 选项不会传递给链接器,编译器认为这些选项是针对他的。

f2py 生成的 ifort 命令如下所示:

ifort.exe -dll -dll Pymodule.o fortranobject.o FortranModule.o module-f2pywrappers2.o -LC:\Anaconda\libs -LC:\Anaconda\PCbuild\amd64 -lPython27

我不知道为什么“-dll”重复了两次(我不得不从原来的“-shared”更改那个标志)。

现在,我尝试查看 f2py 和 distutils 代码,但还没有弄清楚如何在命令输出中添加额外的 /link 。我什至无法找到生成此输出的位置。

如果有人过去遇到过这个问题和/或可能有一些建议,我将非常感激。

感谢您的时间

4

2 回答 2

3

前段时间我自己的代码也遇到过类似的问题。如果我正确理解这些评论,您已经使用了对我有用的方法,所以这只是对所有那些与 f2py 和依赖关系斗争的人的澄清和总结:

f2py 似乎在解决对外部源文件的依赖方面存在问题。但是,如果外部依赖项作为已编译的目标文件传递给 f2py,则链接工作正常,并且 python 库可以毫无问题地构建。

因此,最简单的解决方案似乎是:

  1. 使用您喜欢的编译器和编译器设置将所有依赖项编译到目标文件 (*.o)
  2. 将所有目标文件连同主子程序/函数/模块/的源文件一起传递给 f2py ...
  3. 按预期使用生成的python库

一个简单的 python 脚本可能如下所示(pycompile.py):

#!python.exe
# -*- coding: UTF-8 -*-
import os
import platform
'''Uses f2py to compile needed library'''
# build command-strings
# command for compling *.o and *.mod files
fortran_exe = "gfortran "
# fortran compiler settings
fortran_flags = "<some_gfortran_flags> "
# add path to source code
fortran_source = ("./relative/path/to/source_1.f90 "
                  "C:/absolut/path/to/source_2.f90 "                 
                  "...")
# assemble fortran command
fortran_cmd = fortran_exe + fortran_flags + fortran_source

# command for compiling main source file using f2py
f2py_exe = "f2py -c "
# special compiler-options for Linux/ Windows
if (platform.system() == 'Linux'):
    f2py_flags = "--compiler=unix --fcompiler=gnu95 "
elif (platform.system() == 'Windows'):
    f2py_flags = "--compiler=mingw32 --fcompiler=gnu95 "
# add path to source code/ dependencies
f2py_source = ("-m for_to_py_lib "
               "./path/to/main_source.f90 "
               "source_1.o "
               "source_2.o "
               "... "
               )
# assemble f2py command
f2py_cmd = f2py_exe + f2py_flags + f2py_source

# compile .o and .mod files
print "compiling object- and module-files..."
print
print fortran_cmd
os.system(fortran_cmd)
# compile main_source.f90 with f2py
print "================================================================"
print "start f2py..."
print
print f2py_cmd
os.system(f2py_cmd)

可以通过 Makefile 为大型项目提供更灵活的解决方案,正如@bdforbes在评论(供参考)中讨论的那样,或者结合上述脚本的自定义 CMake 用户命令:

###############################################################################
# General project properties
################################################################################
# Set Project Name
project (for_to_py_lib)
# Set Version Number
set (for_to_py_lib_VERSION_MAJOR 1)
set (for_to_py_lib_VERSION_MINOR 0)
# save folder locations for later use/ scripting (see pycompile.py)
# relative to SOURCE folder
set(source_root ${CMAKE_CURRENT_LIST_DIR}/SOURCE) # save top level source dir for later use
set(lib_root ${CMAKE_CURRENT_LIST_DIR}/LIBRARIES) # save top level lib dir for later use
# relative to BUILD folder
set(build_root ${CMAKE_CURRENT_BINARY_DIR}) # save top level build dir for later use

###
### Fortran to Python library
###
find_package(PythonInterp)
if (PYTHONINTERP_FOUND)
    # copy python compile skript file to build folder and substitute CMake variables
    configure_file(${source_root}/pycompile.py ${build_root}/pycompile.py @ONLY)
    # define for_to_py library ending
    if (UNIX)
        set(CMAKE_PYTHON_LIBRARY_SUFFIX .so)
    elseif (WIN32)
        set(CMAKE_PYTHON_LIBRARY_SUFFIX .pyd)
    endif()
    # add custom target to ALL, building the for_to_py python library (using f2py)
    add_custom_target(for_to_py ALL
                      DEPENDS ${build_root}/for_to_py${CMAKE_PYTHON_LIBRARY_SUFFIX})
    # build command for python library (execute python script pycompile.py containing the actual build commands)
    add_custom_command(OUTPUT ${build_root}/for_to_py${CMAKE_PYTHON_LIBRARY_SUFFIX}
                       COMMAND ${PYTHON_EXECUTABLE} ${build_root}/pycompile.py
                       WORKING_DIRECTORY ${build_root}
                       DEPENDS ${build_root}/pycompile.py
                               ${source_root}/path/to/source_1.f90
                               ${source_root}/path/to/source_2.f90
                               ${source_root}/INOUT/s4binout.f90
                       COMMENT "Generating fortran to python library")
    # post build command for python library (copying of generated files)
    add_custom_command(TARGET for_to_py
                       POST_BUILD
                       COMMAND ${CMAKE_COMMAND} -E copy_if_different 
                               ${build_root}/s4_to_py${CMAKE_PYTHON_LIBRARY_SUFFIX}
                               ${lib_root}/for_to_py${CMAKE_PYTHON_LIBRARY_SUFFIX}
                       COMMENT "\
***************************************************************************************************\n\
 copy of python library for_to_py${CMAKE_PYTHON_LIBRARY_SUFFIX} placed in ${lib_root}/for_to_py${CMAKE_PYTHON_LIBRARY_SUFFIX} \n\
***************************************************************************************************"
                       )
endif (PYTHONINTERP_FOUND)

修改后的pycompile:

#!python.exe
# -*- coding: UTF-8 -*-
...
fortran_source = ("@source_root@/source_1.f90 "
                  "@source_root@/source_2.f90 "                 
                  "...")
...
# add path to source code/ dependencies
f2py_source = ("-m for_to_py_lib "
               "@build_root@/for_to_py.f90 "
               "source_1.o "
               "source_2.o "
               "... "
               )
...

# compile .o and .mod files
...
于 2015-11-09T15:52:31.230 回答
0

使用 /LIBPATH 而不是 /L 指定库路径

于 2015-07-09T19:14:23.817 回答