f2py с компилятором Intel Fortran

Я пытаюсь использовать f2py для взаимодействия моих программ Python с моими модулями Fortran.

Я использую платформу Win7.

Я использую последнюю версию Anaconda 64 (1.7) в качестве стека Python + NumPy.

Мой компилятор Fortran - это последний компилятор Intel Fortran 64 (версия 14.0.0.103, сборка 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 не передаются компоновщику, и компилятор считает, что они адресованы ему.

Команда ifort, сгенерированная f2py, выглядит так:

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, но не понял, как добавить дополнительную ссылку / в выводе команды. Я даже не смог определить, где генерируется этот вывод.

Если кто-то сталкивался с этой проблемой в прошлом и / или может иметь какие-то предложения, я был бы очень признателен.

Спасибо за уделенное время


person Tesla    schedule 11.10.2013    source источник
comment
Я столкнулся с подобными проблемами, но, к сожалению, не смог их обойти; В итоге я создал Makefile, который все собрал воедино. Вот Makefile: pastebin.com/ChSxLzSb.   -  person bdforbes    schedule 15.10.2013
comment
Спасибо за файл! У меня появилась возможность взглянуть на это только сегодня. В конечном итоге заставить его работать было огромной проблемой из-за большого количества возня с путями и различных файлов для выборки. Но, в конце концов, я смог сделать то, что хотел. Я думаю, что очень сложно прийти к окончательному ответу, поскольку он сильно зависит от установленной платформы и цепочек инструментов.   -  person Tesla    schedule 21.10.2013
comment
Итак, каков был ваш подход в итоге? Удалось ли вам взломать distutils в подчинение?   -  person bdforbes    schedule 22.10.2013
comment
Неа. Взломать ваш make-файл было намного проще ... Я мог бы дать еще один шанс на distutils в ближайшие недели. Я обязательно дам вам знать, если найду что-нибудь полезное.   -  person Tesla    schedule 23.10.2013
comment
Немного поздно, но ... Путь к библиотеке указан с помощью / LIBPATH, а не / L   -  person cup    schedule 11.02.2015
comment
@cup опубликуйте это как ответ, чтобы этот вопрос можно было пометить как закрытый. Спасибо.   -  person rocky    schedule 09.07.2015


Ответы (2)


Некоторое время назад я столкнулся с похожими проблемами с моим собственным кодом. Если я правильно понимаю комментарии, вы уже использовали подход, который сработал для меня, поэтому это просто пояснение и резюме для всех, кто борется с f2py и зависимостями:

Похоже, что у f2py проблемы с разрешением зависимостей от внешних исходных файлов. Если внешние зависимости передаются в f2py как уже скомпилированные объектные файлы, связывание работает нормально, и библиотека python получает сборку без проблем.

Поэтому кажется, что самое простое решение:

  1. скомпилировать все зависимости в объектные файлы (* .o), используя предпочтительный компилятор и настройки компилятора
  2. передать все объектные файлы в f2py вместе с исходным файлом вашей основной подпрограммы / function / module / ...
  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
...
person Max Graser    schedule 09.11.2015

Путь к библиотеке указывается с помощью / LIBPATH, а не / L

person cup    schedule 09.07.2015
comment
Спасибо. Извините за позднюю обратную связь, я не заметил комментарий февраль ... Это не совсем ответ на вопрос. Фактически, для ifort это будет / libdir. Настоящий вопрос заключается в том, как изменить способ, которым dist-utils генерирует список аргументов компилятора? На данный момент решение bdforbes по использованию make-файла работает, но было бы неплохо, если бы f2py мог просто справиться со всем этим. - person Tesla; 10.07.2015