0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python 3.12 + Windows で f2py を Intel oneAPI 2024 (ifx) で使う方法

Posted at

はじめに

Python 3.12以降では、NumPyのf2pyがmesonバックエンドを使用するようになりました。これにより、従来の--fcompilerオプションが使えなくなり、Intel Fortranコンパイラ(ifx)を使う場合は追加の設定が必要になります。

本記事では、Windows環境でPython 3.12 + Intel oneAPI 2024のifxを使ってf2pyでFortran拡張モジュールをビルドする方法を解説します。

環境

  • Windows 10/11 または Windows Server
  • Python 3.12以降
  • NumPy 2.x
  • Intel oneAPI 2024.2 (ifx)
  • Visual Studio 2022 (MSVCリンカ用)
  • meson, ninja

問題点

Python 3.12以降でf2pyを使おうとすると、以下のエラーが発生します:

Cannot use distutils backend with Python>=3.12, using meson backend instead.

さらに、Intel Fortranを使おうとしても:

  1. mesonがデフォルトでgfortranを探す
  2. ifxを見つけても、シンボル名の規約が合わない(大文字 vs 小文字、下線の有無)

解決方法

1. 必要なパッケージのインストール

pip install numpy meson ninja

2. meson native fileの作成

Intel Fortranのパスとコンパイルオプションを指定するnative fileを作成します。

meson_intel.ini:

[binaries]
fc = 'C:/Program Files (x86)/Intel/oneAPI/compiler/2024.2/bin/ifx.exe'

[built-in options]
fortran_args = ['/assume:underscore', '/names:lowercase']

重要なオプション:

  • /assume:underscore: サブルーチン名に下線サフィックスを追加
  • /names:lowercase: シンボル名を小文字に統一

これらがないと、f2pyが生成するCラッパーが期待するシンボル名(add_arrays_)とFortranが生成するシンボル名(ADD_ARRAYS)が一致しません。

3. ビルドスクリプト

以下のPythonスクリプトでビルドを自動化できます。

build_f2py.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
f2pyでFortranモジュールをビルド(Intel Fortran使用)
"""

import subprocess
import sys
import os
import shutil
import glob


def find_intel_fortran():
    """Intel Fortranコンパイラのパスを探す"""
    possible_paths = [
        r"C:\Program Files (x86)\Intel\oneAPI\compiler\2024.2\bin\ifx.exe",
        r"C:\Program Files (x86)\Intel\oneAPI\compiler\2024.1\bin\ifx.exe",
        r"C:\Program Files (x86)\Intel\oneAPI\compiler\latest\bin\ifx.exe",
    ]
    for path in possible_paths:
        if os.path.exists(path):
            return path
    return None


def main():
    script_dir = os.path.dirname(os.path.abspath(__file__))
    os.chdir(script_dir)

    # Intel Fortranを探す
    ifx_path = find_intel_fortran()
    if ifx_path is None:
        print("ERROR: Intel Fortran (ifx) not found!")
        return 1

    print(f"Found Intel Fortran: {ifx_path}")

    # meson native fileを作成
    ifx_path_escaped = ifx_path.replace("\\", "/")
    native_file_content = f"""[binaries]
fc = '{ifx_path_escaped}'

[built-in options]
fortran_args = ['/assume:underscore', '/names:lowercase']
"""
    native_file = os.path.join(script_dir, "meson_intel.ini")
    with open(native_file, "w") as f:
        f.write(native_file_content)

    # 環境変数を設定
    env = os.environ.copy()
    intel_bin = os.path.dirname(ifx_path)
    env["PATH"] = intel_bin + ";" + env.get("PATH", "")
    env["FC"] = ifx_path

    # Step 1: f2pyでCラッパーを生成
    print("Step 1: Generating C wrapper with f2py...")
    subprocess.run([
        sys.executable, "-m", "numpy.f2py",
        "your_module.f90",  # ここを変更
        "-m", "your_module",  # ここを変更
        "-h", "your_module.pyf",
        "--overwrite-signature"
    ], env=env, check=True)

    subprocess.run([
        sys.executable, "-m", "numpy.f2py",
        "your_module.pyf"
    ], env=env, check=True)

    # Step 2: mesonでビルド
    print("Step 2: Building with meson...")
    build_dir = os.path.join(script_dir, "build")
    if os.path.exists(build_dir):
        shutil.rmtree(build_dir)

    subprocess.run([
        "meson", "setup", "build",
        f"--native-file={native_file}",
        "--buildtype=release"
    ], env=env, cwd=script_dir, check=True)

    subprocess.run([
        "meson", "compile", "-C", "build"
    ], env=env, cwd=script_dir, check=True)

    # .pydファイルをコピー
    for pyd in glob.glob(os.path.join(build_dir, "*.pyd")):
        shutil.copy(pyd, script_dir)
        print(f"Created: {os.path.basename(pyd)}")

    return 0


if __name__ == "__main__":
    sys.exit(main())

4. meson.buildの作成

mesonでビルドするために、meson.buildファイルが必要です。

meson.build:

project('your_module', 'c', 'fortran',
  version: '0.1',
)

py = import('python').find_installation(pure: false)
py_dep = py.dependency()

incdir_numpy = run_command(py,
  ['-c', 'import numpy; print(numpy.get_include())'],
  check: true
).stdout().strip()

incdir_f2py = run_command(py,
  ['-c', 'import numpy.f2py; print(numpy.f2py.get_include())'],
  check: true
).stdout().strip()

inc_dirs = include_directories(incdir_numpy, incdir_f2py)

py.extension_module('your_module',
  'your_module.f90',
  'your_modulemodule.c',  # f2pyが生成
  incdir_f2py / 'fortranobject.c',
  include_directories: inc_dirs,
  dependencies: py_dep,
  install: true
)

5. サンプルFortranコード

test_simple.f90:

subroutine add_arrays(a, b, c, n)
    implicit none
    integer, intent(in) :: n
    real(8), intent(in) :: a(n), b(n)
    real(8), intent(out) :: c(n)
    !f2py intent(in) :: a, b
    !f2py intent(out) :: c
    !f2py intent(hide) :: n

    integer :: i
    do i = 1, n
        c(i) = a(i) + b(i)
    end do
end subroutine

subroutine dot_product_f(a, b, result, n)
    implicit none
    integer, intent(in) :: n
    real(8), intent(in) :: a(n), b(n)
    real(8), intent(out) :: result
    !f2py intent(in) :: a, b
    !f2py intent(out) :: result
    !f2py intent(hide) :: n

    result = dot_product(a, b)
end subroutine

使用例

ビルド後、Pythonから以下のように呼び出せます:

import numpy as np
import test_fortran

# 配列加算
a = np.array([1.0, 2.0, 3.0])
b = np.array([4.0, 5.0, 6.0])
c = test_fortran.add_arrays(a, b)
print(f"add_arrays result: {c}")  # [5. 7. 9.]

# 内積
result = test_fortran.dot_product_f(a, b)
print(f"dot_product result: {result}")  # 32.0

トラブルシューティング

LNK2001: 外部シンボル xxx_ は未解決です

Fortranのシンボル名規約が合っていません。meson native fileに以下を追加してください:

fortran_args = ['/assume:underscore', '/names:lowercase']

python312_d.lib が見つからない

デバッグビルドになっています。--buildtype=releaseを指定してください。

ifxが見つからない

環境変数FCにifxのフルパスを設定してください:

env["FC"] = r"C:\Program Files (x86)\Intel\oneAPI\compiler\2024.2\bin\ifx.exe"

ifortが使われる

NumPy 2.xのmesonバックエンドはifortよりifxを優先しますが、環境によってはifortが選ばれることがあります。FC環境変数で明示的にifxを指定してください。

まとめ

Python 3.12以降でf2pyとIntel Fortran (ifx) を使うには:

  1. meson native fileでifxのパスとコンパイルオプションを指定
  2. **/assume:underscore/names:lowercase**オプションでシンボル名の規約を合わせる
  3. **環境変数FC**でifxを明示的に指定
  4. **--buildtype=release**でリリースビルドを指定

これにより、Intel Fortranの高性能な最適化を活かしたPython拡張モジュールを作成できます。

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?