NumPy-源码解析-九-

36 阅读1小时+

NumPy 源码解析(九)

.\numpy\numpy\f2py\diagnose.py

#!/usr/bin/env python3
# 导入必要的模块
import os  # 导入操作系统接口模块
import sys  # 导入系统特定的参数和函数模块
import tempfile  # 导入临时文件和目录创建模块


# 定义一个函数,用于执行系统命令并打印输出
def run_command(cmd):
    # 打印即将执行的命令
    print('Running %r:' % (cmd))
    # 执行系统命令
    os.system(cmd)
    # 打印分隔线
    print('------')


# 定义主程序函数
def run():
    _path = os.getcwd()  # 获取当前工作目录并保存
    os.chdir(tempfile.gettempdir())  # 切换工作目录到系统临时目录
    # 打印分隔线
    print('------')
    # 打印操作系统名称
    print('os.name=%r' % (os.name))
    # 打印分隔线
    print('------')
    # 打印系统平台信息
    print('sys.platform=%r' % (sys.platform))
    # 打印分隔线
    print('------')
    # 打印Python解释器版本信息
    print('sys.version:')
    print(sys.version)
    # 打印分隔线
    print('------')
    # 打印Python解释器安装路径前缀
    print('sys.prefix:')
    print(sys.prefix)
    # 打印分隔线
    print('------')
    # 打印Python模块搜索路径
    print('sys.path=%r' % (':'.join(sys.path)))
    # 打印分隔线
    print('------')

    # 尝试导入新版numpy模块
    try:
        import numpy
        has_newnumpy = 1
    except ImportError as e:
        # 若导入失败,打印错误信息
        print('Failed to import new numpy:', e)
        has_newnumpy = 0

    # 尝试导入f2py2e模块
    try:
        from numpy.f2py import f2py2e
        has_f2py2e = 1
    except ImportError as e:
        # 若导入失败,打印错误信息
        print('Failed to import f2py2e:', e)
        has_f2py2e = 0

    # 尝试导入numpy的distutils模块
    try:
        import numpy.distutils
        has_numpy_distutils = 2
    except ImportError:
        try:
            import numpy_distutils
            has_numpy_distutils = 1
        except ImportError as e:
            # 若导入失败,打印错误信息
            print('Failed to import numpy_distutils:', e)
            has_numpy_distutils = 0

    # 若成功导入新版numpy模块,打印其版本信息和文件路径
    if has_newnumpy:
        try:
            print('Found new numpy version %r in %s' %
                  (numpy.__version__, numpy.__file__))
        except Exception as msg:
            # 若获取信息失败,打印错误信息
            print('error:', msg)
            print('------')

    # 若成功导入f2py2e模块,打印其版本信息和文件路径
    if has_f2py2e:
        try:
            print('Found f2py2e version %r in %s' %
                  (f2py2e.__version__.version, f2py2e.__file__))
        except Exception as msg:
            # 若获取信息失败,打印错误信息
            print('error:', msg)
            print('------')

    os.chdir(_path)  # 恢复原始工作目录
# 如果脚本作为主程序运行,则执行run函数
if __name__ == "__main__":
    run()

.\numpy\numpy\f2py\f2py2e.py

#!/usr/bin/env python3
"""

f2py2e - Fortran to Python C/API generator. 2nd Edition.
         See __usage__ below.

Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.

NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
"""
# 导入必要的标准库模块
import sys              # 导入 sys 模块,提供对系统参数和功能的访问
import os               # 导入 os 模块,提供了对操作系统进行调用的接口
import pprint           # 导入 pprint 模块,用于打印 Python 数据结构,美观打印字典和列表等
import re               # 导入 re 模块,提供正则表达式的支持
from pathlib import Path   # 导入 pathlib 中的 Path 类,用于处理文件和目录路径
from itertools import dropwhile   # 导入 itertools 中的 dropwhile 函数,用于迭代直到条件为假
import argparse         # 导入 argparse 模块,用于命令行参数解析
import copy             # 导入 copy 模块,用于对象的浅拷贝和深拷贝

# 导入自定义模块
from . import crackfortran
from . import rules
from . import cb_rules
from . import auxfuncs
from . import cfuncs
from . import f90mod_rules
from . import __version__
from . import capi_maps
from numpy.f2py._backends import f2py_build_generator

# 设置 f2py_version 和 numpy_version 变量为当前版本
f2py_version = __version__.version
numpy_version = __version__.version

# 定义错误信息输出函数
errmess = sys.stderr.write
# 定义显示函数,使用 pprint.pprint 实现
show = pprint.pprint
# 定义标准输出信息函数
outmess = auxfuncs.outmess

# 判断 Python 版本是否符合要求,设置 MESON_ONLY_VER 为布尔值
MESON_ONLY_VER = (sys.version_info >= (3, 12))

# 定义程序用法说明字符串
__usage__ =\
f"""Usage:

1) To construct extension module sources:

      f2py [<options>] <fortran files> [[[only:]||[skip:]] \\
                                        <fortran functions> ] \\
                                       [: <fortran files> ...]

2) To compile fortran files and build extension modules:

      f2py -c [<options>, <build_flib options>, <extra options>] <fortran files>

3) To generate signature files:

      f2py -h <filename.pyf> ...< same options as in (1) >

Description: This program generates a Python C/API file (<modulename>module.c)
             that contains wrappers for given fortran functions so that they
             can be called from Python. With the -c option the corresponding
             extension modules are built.
"""
Options:

# -h <filename>    Write signatures of the fortran routines to file <filename>
#                  and exit. You can then edit <filename> and use it instead
#                  of <fortran files>. If <filename>==stdout then the
#                  signatures are printed to stdout.

# <fortran functions>  Names of fortran routines for which Python C/API
#                      functions will be generated. Default is all that are found
#                      in <fortran files>.

# <fortran files>  Paths to fortran/signature files that will be scanned for
#                  <fortran functions> in order to determine their signatures.

# skip:            Ignore fortran functions that follow until `:'.

# only:            Use only fortran functions that follow until `:'.

# :                Get back to <fortran files> mode.

# -m <modulename>  Name of the module; f2py generates a Python/C API
#                  file <modulename>module.c or extension module <modulename>.
#                  Default is 'untitled'.

# '-include<header>'  Writes additional headers in the C wrapper, can be passed
#                     multiple times, generates #include <header> each time.

# --[no-]lower     Do [not] lower the cases in <fortran files>. By default,
#                  --lower is assumed with -h key, and --no-lower without -h key.

# --build-dir <dirname>  All f2py generated files are created in <dirname>.
#                  Default is tempfile.mkdtemp().

# --overwrite-signature  Overwrite existing signature file.

# --[no-]latex-doc Create (or not) <modulename>module.tex.
#                  Default is --no-latex-doc.

# --short-latex    Create 'incomplete' LaTeX document (without commands
#                  \\documentclass, \\tableofcontents, and \\begin{{document}},
#                  \\end{{document}}).

# --[no-]rest-doc Create (or not) <modulename>module.rst.
#                  Default is --no-rest-doc.

# --debug-capi     Create C/API code that reports the state of the wrappers
#                  during runtime. Useful for debugging.

# --[no-]wrap-functions    Create Fortran subroutine wrappers to Fortran 77
#                  functions. --wrap-functions is default because it ensures
#                  maximum portability/compiler independence.

# --include-paths <path1>:<path2>:...   Search include files from the given
#                  directories.

# --help-link [..] List system resources found by system_info.py. See also
#                  --link-<resource> switch below. [..] is optional list
#                  of resources names. E.g. try 'f2py --help-link lapack_opt'.

# --f2cmap <filename>  Load Fortran-to-Python KIND specification from the given
#                  file. Default: .f2py_f2cmap in current directory.

# --quiet          Run quietly.

# --verbose        Run with extra verbosity.

# --skip-empty-wrappers   Only generate wrapper files when needed.

# -v               Print f2py version ID and exit.
# 构建后端选项(仅对使用 -c 有效)
# [NO_MESON] 用于指示不应与 meson 后端或 Python 3.12 以上版本一起使用的选项:

# --fcompiler=         指定 Fortran 编译器类型按供应商分类 [NO_MESON]
# --compiler=          指定 distutils C 编译器类型 [NO_MESON]

# --help-fcompiler     列出可用的 Fortran 编译器并退出 [NO_MESON]
# --f77exec=           指定 F77 编译器的路径 [NO_MESON]
# --f90exec=           指定 F90 编译器的路径 [NO_MESON]
# --f77flags=          指定 F77 编译器的编译选项
# --f90flags=          指定 F90 编译器的编译选项
# --opt=               指定优化选项 [NO_MESON]
# --arch=              指定与体系结构相关的优化选项 [NO_MESON]
# --noopt              编译时不使用优化 [NO_MESON]
# --noarch             编译时不使用与体系结构相关的优化 [NO_MESON]
# --debug              使用调试信息进行编译

# --dep                <dependency>
#                      为模块指定 meson 依赖项。可以多次传递此选项以指定多个依赖项。
#                      依赖项将存储在一个列表中以供进一步处理。

#                      示例: --dep lapack --dep scalapack
#                      这将识别 "lapack" 和 "scalapack" 作为依赖项,并从 argv 中删除它们,留下一个包含 ["lapack", "scalapack"] 的依赖项列表。

# --backend            <backend_type>
#                      指定编译过程的构建后端类型。支持的后端包括 'meson' 和 'distutils'。
#                      如果未指定,默认为 'distutils'。在 Python 3.12 或更高版本中,默认为 'meson'。

# 额外选项(仅在使用 -c 有效):

# --link-<resource>    将扩展模块与 numpy.distutils/system_info.py 中定义的资源链接起来。
#                      例如,要链接优化的 LAPACK 库(在 MacOSX 上是 vecLib,在其他地方是 ATLAS),使用 --link-lapack_opt。
#                      参见 --help-link 开关。 [NO_MESON]

# -L/path/to/lib/ -l<libname>
# -D<define> -U<name>
# -I/path/to/include/
# <filename>.o <filename>.so <filename>.a

# 对于非 gcc Fortran 编译器,可能需要使用以下宏:
#   -DPREPEND_FORTRAN -DNO_APPEND_FORTRAN -DUPPERCASE_FORTRAN

# 使用 -DF2PY_REPORT_ATEXIT 时,在退出时打印 F2PY 接口的性能报告(平台:Linux)。

# 使用 -DF2PY_REPORT_ON_ARRAY_COPY=<int> 时,每当 F2PY 接口复制数组时,将向 stderr 发送一条消息。
# 整数 <int> 设置了在应显示消息的数组大小阈值。

Version:     {f2py_version}
numpy Version: {numpy_version}
License:     NumPy license (see LICENSE.txt in the NumPy source code)
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
# 定义函数 scaninputline,用于处理输入行,返回多个变量的初始值
def scaninputline(inputline):
    # 初始化空列表,用于存储文件名、跳过函数名、仅包含函数名、调试信息
    files, skipfuncs, onlyfuncs, debug = [], [], [], []
    # 初始化多个标志变量和计数变量
    f, f2, f3, f5, f6, f8, f9, f10 = 1, 0, 0, 0, 0, 0, 0, 0
    # 设定详细输出标志为1
    verbose = 1
    # 设定空生成器标志为真
    emptygen = True
    # 设定 dolc 变量为 -1
    dolc = -1
    # 设定 dolatexdoc 和 dorestdoc 变量为 0
    dolatexdoc = 0
    dorestdoc = 0
    # 设定 wrapfuncs 变量为 1
    wrapfuncs = 1
    # 设定 buildpath 变量为当前路径字符串
    buildpath = '.'
    # 调用 get_includes 函数,获取包含路径列表和更新的 inputline
    include_paths, inputline = get_includes(inputline)
    # 初始化 signsfile 和 modulename 变量为 None
    signsfile, modulename = None, None
    # 初始化 options 字典,包含 buildpath 键和空值,coutput 键和空值,f2py_wrapper_output 键和空值
    options = {'buildpath': buildpath,
               'coutput': None,
               'f2py_wrapper_output': None}
    # 遍历输入的每一行
    for l in inputline:
        # 如果当前行为空字符串,则跳过
        if l == '':
            pass
        # 如果当前行为'only:',设置标志位f为0
        elif l == 'only:':
            f = 0
        # 如果当前行为'skip:',设置标志位f为-1
        elif l == 'skip:':
            f = -1
        # 如果当前行为':',设置标志位f为1
        elif l == ':':
            f = 1
        # 如果当前行以'--debug-'开头,将后面的内容添加到debug列表中
        elif l[:8] == '--debug-':
            debug.append(l[8:])
        # 如果当前行为'--lower',设置dolc标志为1
        elif l == '--lower':
            dolc = 1
        # 如果当前行为'--build-dir',设置f6标志为1
        elif l == '--build-dir':
            f6 = 1
        # 如果当前行为'--no-lower',设置dolc标志为0
        elif l == '--no-lower':
            dolc = 0
        # 如果当前行为'--quiet',设置verbose标志为0
        elif l == '--quiet':
            verbose = 0
        # 如果当前行为'--verbose',增加verbose计数
        elif l == '--verbose':
            verbose += 1
        # 如果当前行为'--latex-doc',设置dolatexdoc标志为1
        elif l == '--latex-doc':
            dolatexdoc = 1
        # 如果当前行为'--no-latex-doc',设置dolatexdoc标志为0
        elif l == '--no-latex-doc':
            dolatexdoc = 0
        # 如果当前行为'--rest-doc',设置dorestdoc标志为1
        elif l == '--rest-doc':
            dorestdoc = 1
        # 如果当前行为'--no-rest-doc',设置dorestdoc标志为0
        elif l == '--no-rest-doc':
            dorestdoc = 0
        # 如果当前行为'--wrap-functions',设置wrapfuncs标志为1
        elif l == '--wrap-functions':
            wrapfuncs = 1
        # 如果当前行为'--no-wrap-functions',设置wrapfuncs标志为0
        elif l == '--no-wrap-functions':
            wrapfuncs = 0
        # 如果当前行为'--short-latex',设置options字典中的'shortlatex'为1
        elif l == '--short-latex':
            options['shortlatex'] = 1
        # 如果当前行为'--coutput',设置f8标志为1
        elif l == '--coutput':
            f8 = 1
        # 如果当前行为'--f2py-wrapper-output',设置f9标志为1
        elif l == '--f2py-wrapper-output':
            f9 = 1
        # 如果当前行为'--f2cmap',设置f10标志为1
        elif l == '--f2cmap':
            f10 = 1
        # 如果当前行为'--overwrite-signature',设置options字典中的'h-overwrite'为1
        elif l == '--overwrite-signature':
            options['h-overwrite'] = 1
        # 如果当前行为'-h',设置f2标志为1
        elif l == '-h':
            f2 = 1
        # 如果当前行为'-m',设置f3标志为1
        elif l == '-m':
            f3 = 1
        # 如果当前行以'-v'开头,打印f2py_version并退出程序
        elif l[:2] == '-v':
            print(f2py_version)
            sys.exit()
        # 如果当前行为'--show-compilers',设置f5标志为1
        elif l == '--show-compilers':
            f5 = 1
        # 如果当前行以'-include'开头,将该行内容添加到相应列表和字典中
        elif l[:8] == '-include':
            cfuncs.outneeds['userincludes'].append(l[9:-1])
            cfuncs.userincludes[l[9:-1]] = '#include ' + l[8:]
        # 如果当前行为'--skip-empty-wrappers',设置emptygen为False
        elif l == '--skip-empty-wrappers':
            emptygen = False
        # 如果当前行以'-'开头但不符合以上任何规则,打印错误消息并退出程序
        elif l[0] == '-':
            errmess('Unknown option %s\n' % repr(l))
            sys.exit()
        # 如果f2标志为真,将当前行作为文件名存入files列表,f2标志置为0
        elif f2:
            f2 = 0
            signsfile = l
        # 如果f3标志为真,将当前行作为模块名存入modulename,f3标志置为0
        elif f3:
            f3 = 0
            modulename = l
        # 如果f6标志为真,将当前行作为构建路径存入buildpath,f6标志置为0
        elif f6:
            f6 = 0
            buildpath = l
        # 如果f8标志为真,将当前行作为选项字典中的'coutput'存入options,f8标志置为0
        elif f8:
            f8 = 0
            options["coutput"] = l
        # 如果f9标志为真,将当前行作为选项字典中的'f2py_wrapper_output'存入options,f9标志置为0
        elif f9:
            f9 = 0
            options["f2py_wrapper_output"] = l
        # 如果f10标志为真,将当前行作为选项字典中的'f2cmap_file'存入options,f10标志置为0
        elif f10:
            f10 = 0
            options["f2cmap_file"] = l
        # 如果f为1,尝试打开当前行对应的文件并将其加入files列表,如果出现OSError则打印错误消息
        elif f == 1:
            try:
                with open(l):
                    pass
                files.append(l)
            except OSError as detail:
                errmess(f'OSError: {detail!s}. Skipping file "{l!s}".\n')
        # 如果f为-1,将当前行加入skipfuncs列表
        elif f == -1:
            skipfuncs.append(l)
    # 如果f5标志为假且files和modulename都为空,则打印__usage__并退出程序
    if not f5 and not files and not modulename:
        print(__usage__)
        sys.exit()
    # 如果buildpath不是一个目录,且verbose标志为假,则输出创建buildpath的信息
    if not os.path.isdir(buildpath):
        if not verbose:
            outmess('Creating build directory %s\n' % (buildpath))
        # 创建buildpath目录
        os.mkdir(buildpath)
    # 如果signsfile有值,则将其路径设置为buildpath和signsfile的组合路径
    if signsfile:
        signsfile = os.path.join(buildpath, signsfile)
    # 检查是否提供了签名文件路径,并且该路径指向一个文件,同时选项中没有 'h-overwrite'
    if signsfile and os.path.isfile(signsfile) and 'h-overwrite' not in options:
        # 如果满足条件,则输出错误信息并退出程序
        errmess(
            'Signature file "%s" exists!!! Use --overwrite-signature to overwrite.\n' % (signsfile))
        sys.exit()

    # 将函数选项传递给选项字典
    options['emptygen'] = emptygen
    options['debug'] = debug
    options['verbose'] = verbose

    # 根据 dolc 变量的值设置 'do-lower' 选项,如果 dolc 为 -1 并且没有提供签名文件,则设置为 0
    if dolc == -1 and not signsfile:
        options['do-lower'] = 0
    else:
        options['do-lower'] = dolc

    # 如果提供了模块名称,则将其添加到选项字典中的 'module' 键
    if modulename:
        options['module'] = modulename

    # 如果提供了签名文件路径,则将其添加到选项字典中的 'signsfile' 键
    if signsfile:
        options['signsfile'] = signsfile

    # 如果提供了 onlyfuncs,则将其添加到选项字典中的 'onlyfuncs' 键
    if onlyfuncs:
        options['onlyfuncs'] = onlyfuncs

    # 如果提供了 skipfuncs,则将其添加到选项字典中的 'skipfuncs' 键
    if skipfuncs:
        options['skipfuncs'] = skipfuncs

    # 将 dolatexdoc 的值设置为选项字典中的 'dolatexdoc' 键
    options['dolatexdoc'] = dolatexdoc

    # 将 dorestdoc 的值设置为选项字典中的 'dorestdoc' 键
    options['dorestdoc'] = dorestdoc

    # 将 wrapfuncs 的值设置为选项字典中的 'wrapfuncs' 键
    options['wrapfuncs'] = wrapfuncs

    # 将 buildpath 的值设置为选项字典中的 'buildpath' 键
    options['buildpath'] = buildpath

    # 将 include_paths 的值设置为选项字典中的 'include_paths' 键
    options['include_paths'] = include_paths

    # 设置 'f2cmap_file' 键的默认值为 None,如果已经存在则不改变
    options.setdefault('f2cmap_file', None)

    # 返回 files 和 options 作为函数的结果
    return files, options
# 定义一个函数 `callcrackfortran`,用于调用 crackfortran 进行处理,接受文件列表和选项参数。
def callcrackfortran(files, options):
    # 设置全局变量 rules.options 为传入的选项参数
    rules.options = options
    # 设置 crackfortran 的调试模式为 options 中的 debug 值
    crackfortran.debug = options['debug']
    # 设置 crackfortran 的详细输出模式为 options 中的 verbose 值
    crackfortran.verbose = options['verbose']
    # 如果 options 中包含 'module',则设置 crackfortran.f77modulename 为对应值
    if 'module' in options:
        crackfortran.f77modulename = options['module']
    # 如果 options 中包含 'skipfuncs',则设置 crackfortran.skipfuncs 为对应值
    if 'skipfuncs' in options:
        crackfortran.skipfuncs = options['skipfuncs']
    # 如果 options 中包含 'onlyfuncs',则设置 crackfortran.onlyfuncs 为对应值
    if 'onlyfuncs' in options:
        crackfortran.onlyfuncs = options['onlyfuncs']
    # 设置 crackfortran.include_paths 为 options 中的 include_paths 列表
    crackfortran.include_paths[:] = options['include_paths']
    # 设置 crackfortran.dolowercase 为 options 中的 do-lower 值
    crackfortran.dolowercase = options['do-lower']
    # 调用 crackfortran.crackfortran 处理文件列表,返回处理后的列表 postlist
    postlist = crackfortran.crackfortran(files)
    # 如果 options 中包含 'signsfile'
    if 'signsfile' in options:
        # 输出保存签名信息到文件的提示信息
        outmess('Saving signatures to file "%s"\n' % (options['signsfile']))
        # 调用 crackfortran.crack2fortran 处理 postlist,返回处理后的结果 pyf
        pyf = crackfortran.crack2fortran(postlist)
        # 如果 options['signsfile'] 的后六个字符为 'stdout'
        if options['signsfile'][-6:] == 'stdout':
            # 将处理结果 pyf 输出到标准输出
            sys.stdout.write(pyf)
        else:
            # 将处理结果 pyf 写入到 options['signsfile'] 指定的文件中
            with open(options['signsfile'], 'w') as f:
                f.write(pyf)
    # 如果 options["coutput"] 为 None
    if options["coutput"] is None:
        # 遍历 postlist 中的每个模块 mod
        for mod in postlist:
            # 设置 mod 的 "coutput" 属性为 "%smodule.c" % mod["name"]
            mod["coutput"] = "%smodule.c" % mod["name"]
    else:
        # 否则,遍历 postlist 中的每个模块 mod
        for mod in postlist:
            # 设置 mod 的 "coutput" 属性为 options["coutput"]
            mod["coutput"] = options["coutput"]
    # 如果 options["f2py_wrapper_output"] 为 None
    if options["f2py_wrapper_output"] is None:
        # 遍历 postlist 中的每个模块 mod
        for mod in postlist:
            # 设置 mod 的 "f2py_wrapper_output" 属性为 "%s-f2pywrappers.f" % mod["name"]
            mod["f2py_wrapper_output"] = "%s-f2pywrappers.f" % mod["name"]
    else:
        # 否则,遍历 postlist 中的每个模块 mod
        for mod in postlist:
            # 设置 mod 的 "f2py_wrapper_output" 属性为 options["f2py_wrapper_output"]
            mod["f2py_wrapper_output"] = options["f2py_wrapper_output"]
    # 返回处理后的模块列表 postlist
    return postlist


# 定义一个函数 buildmodules,用于构建模块,接受模块列表作为参数 lst
def buildmodules(lst):
    # 调用 cfuncs 模块的 buildcfuncs 函数
    cfuncs.buildcfuncs()
    # 输出建立模块的提示信息
    outmess('Building modules...\n')
    # 初始化模块、模块名称列表和使用关系字典
    modules, mnames, isusedby = [], [], {}
    # 遍历传入的模块列表 lst 中的每个元素 item
    for item in lst:
        # 如果 item 的 'name' 属性中包含 '__user__'
        if '__user__' in item['name']:
            # 调用 cb_rules 模块的 buildcallbacks 函数处理该 item
            cb_rules.buildcallbacks(item)
        else:
            # 否则,如果 item 中包含 'use' 属性
            if 'use' in item:
                # 遍历 item['use'] 字典的键 u
                for u in item['use'].keys():
                    # 如果 u 不在 isusedby 字典中,则将其初始化为一个空列表
                    if u not in isusedby:
                        isusedby[u] = []
                    # 将 item['name'] 加入到 u 在 isusedby 中对应的列表中
                    isusedby[u].append(item['name'])
            # 将 item 加入到模块列表 modules 中
            modules.append(item)
            # 将 item['name'] 加入到模块名称列表 mnames 中
            mnames.append(item['name'])
    # 初始化返回字典 ret
    ret = {}
    # 遍历模块列表 modules 和模块名称列表 mnames 中对应位置的元素 module 和 name
    for module, name in zip(modules, mnames):
        # 如果 name 在 isusedby 中
        if name in isusedby:
            # 输出跳过模块 name 的提示信息,说明它被 isusedby[name] 使用
            outmess('\tSkipping module "%s" which is used by %s.\n' % (
                name, ','.join('"%s"' % s for s in isusedby[name])))
        else:
            # 否则,创建一个空列表 um
            um = []
            # 如果 module 中包含 'use' 属性
            if 'use' in module:
                # 遍历 module['use'] 字典的键 u
                for u in module['use'].keys():
                    # 如果 u 在 isusedby 中,并且 u 在 mnames 中
                    if u in isusedby and u in mnames:
                        # 将 modules[mnames.index(u)] 加入到 um 中
                        um.append(modules[mnames.index(u)])
                    else:
                        # 否则,输出模块 name 使用了不存在的 u 的提示信息
                        outmess(
                            f'\tModule "{name}" uses nonexisting "{u}" '
                            'which will be ignored.\n')
            # 将 rules.buildmodule 处理 module 和 um 后的结果添加到 ret[name] 中
            ret[name] = {}
            dict_append(ret[name], rules.buildmodule(module, um))
    # 返回处理后的模块字典 ret
    return ret


# 定义一个函数 dict_append,用于向目标字典 d_out 中追加源字典 d_in 的内容
def dict_append(d_out, d_in):
    # 遍历源字典 d_in 的键值对 (k, v)
    for (k, v) in d_in.items():
        # 如果目标字典 d_out 中不存在键 k,则初始化一个空列表
        if k not in d_out:
            d_out[k] = []
        # 如果 v 是列表,则将其与 d_out[k] 合并
        if isinstance(v, list):
            d_out[k] = d_out[k] + v
        else:
            # 否则,将 v 添加到 d_out[k] 中
            d_out[k].append(v)


# 定义一个函数 run_main,用于模拟运行 f2py 命令,接受命令行参数列表 comline_list
def run_main(comline_list):
    """
    Equivalent to running::

        f2py <args>
    """
    crackfortran.reset_global_f2py_vars()
    # 重置全局的 f2py 变量,清理之前的状态

    f2pydir = os.path.dirname(os.path.abspath(cfuncs.__file__))
    # 获取当前文件 cfuncs 的绝对路径所在目录名

    fobjhsrc = os.path.join(f2pydir, 'src', 'fortranobject.h')
    # 构建头文件 fortranobject.h 的路径,位于 f2pydir/src 目录下

    fobjcsrc = os.path.join(f2pydir, 'src', 'fortranobject.c')
    # 构建源文件 fortranobject.c 的路径,位于 f2pydir/src 目录下

    # gh-22819 -- begin
    parser = make_f2py_compile_parser()
    # 创建 f2py 编译的解析器对象

    args, comline_list = parser.parse_known_args(comline_list)
    # 使用解析器解析传入的命令行参数列表 comline_list,并获取解析后的参数和剩余的命令行列表

    pyf_files, _ = filter_files("", "[.]pyf([.]src|)", comline_list)
    # 过滤出 comline_list 中的 ".pyf" 文件,并忽略匹配的扩展名 ".src"

    # Checks that no existing modulename is defined in a pyf file
    # TODO: Remove all this when scaninputline is replaced

    if args.module_name:
        if "-h" in comline_list:
            modname = (
                args.module_name
            )  # 当命令行包含 "-h" 选项时,直接使用 args 中的模块名
        else:
            modname = validate_modulename(
                pyf_files, args.module_name
            )  # 当命令行不包含 "-h" 选项时,验证模块名的有效性
        comline_list += ['-m', modname]  # 添加模块名参数到命令行列表,供后续扫描输入行使用

    # gh-22819 -- end

    files, options = scaninputline(comline_list)
    # 使用扫描输入行函数处理命令行列表,获取文件列表和选项字典

    auxfuncs.options = options
    # 设置辅助函数的选项参数

    capi_maps.load_f2cmap_file(options['f2cmap_file'])
    # 加载指定的 f2c 映射文件

    postlist = callcrackfortran(files, options)
    # 调用 crackfortran 处理文件列表和选项,返回处理后的列表

    isusedby = {}
    # 初始化用于存储模块使用信息的字典

    for plist in postlist:
        if 'use' in plist:
            for u in plist['use'].keys():
                if u not in isusedby:
                    isusedby[u] = []
                isusedby[u].append(plist['name'])
    # 遍历处理后的列表,记录模块的使用关系

    for plist in postlist:
        if plist['block'] == 'python module' and '__user__' in plist['name']:
            if plist['name'] in isusedby:
                # if not quiet:
                outmess(
                    f'Skipping Makefile build for module "{plist["name"]}" '
                    'which is used by {}\n'.format(
                        ','.join(f'"{s}"' for s in isusedby[plist['name']])))
    # 遍历处理后的列表,对于 Python 模块且被其他模块使用的情况,输出跳过构建的信息

    if 'signsfile' in options:
        if options['verbose'] > 1:
            outmess(
                'Stopping. Edit the signature file and then run f2py on the signature file: ')
            outmess('%s %s\n' %
                    (os.path.basename(sys.argv[0]), options['signsfile']))
        return
    # 如果选项中包含签名文件,且详细模式大于 1,则输出停止信息,并返回
    # 对于 postlist 中的每个 plist 元素进行迭代
    for plist in postlist:
        # 如果 plist 的 'block' 属性不是 'python module'
        if plist['block'] != 'python module':
            # 如果 options 中不包含 'python module' 选项
            if 'python module' not in options:
                # 打印错误消息,提示用户如何处理 Fortran 源代码
                errmess('Tip: If your original code is Fortran source then you must use -m option.\n')
            # 抛出类型错误,说明所有的块必须是 'python module' 块,但得到了不同的类型
            raise TypeError('All blocks must be python module blocks but got %s' % (repr(plist['block'])))

    # 设置 auxfuncs.debugoptions 为 options 中的 'debug' 值
    auxfuncs.debugoptions = options['debug']
    # 设置 f90mod_rules.options 为 options 对象
    f90mod_rules.options = options
    # 设置 auxfuncs.wrapfuncs 为 options 中的 'wrapfuncs' 值
    auxfuncs.wrapfuncs = options['wrapfuncs']

    # 调用 buildmodules 函数,将 postlist 作为参数,获取返回值并赋给 ret
    ret = buildmodules(postlist)

    # 对于 ret 中的每个模块名 mn,向其对应的字典中添加 'csrc' 和 'h' 两个键,值分别为 fobjcsrc 和 fobjhsrc
    for mn in ret.keys():
        dict_append(ret[mn], {'csrc': fobjcsrc, 'h': fobjhsrc})
    
    # 返回 ret 字典
    return ret
def filter_files(prefix, suffix, files, remove_prefix=None):
    """
    Filter files by prefix and suffix.

    prefix: str, prefix string to match at the beginning of filenames.
    suffix: str, suffix string to match at the end of filenames.
    files: list of str, list of filenames to filter.
    remove_prefix: str or None, if provided, the prefix to remove from filtered filenames.

    Returns:
    filtered: list of str, filenames that match the prefix and suffix criteria.
    rest: list of str, filenames that do not match the criteria.
    """
    filtered, rest = [], []
    # Regular expression pattern to match filenames starting with `prefix` and ending with `suffix`
    match = re.compile(prefix + r'.*' + suffix + r'\Z').match
    if remove_prefix:
        ind = len(prefix)
    else:
        ind = 0
    for file in [x.strip() for x in files]:
        if match(file):
            # Append the filename without the prefix (if `remove_prefix` is specified)
            filtered.append(file[ind:])
        else:
            # Append filenames that do not match the pattern
            rest.append(file)
    return filtered, rest


def get_prefix(module):
    """
    Retrieve the parent directory of the parent directory of the module file.

    module: module object, the module whose parent directories need to be retrieved.

    Returns:
    p: str, parent directory path.
    """
    p = os.path.dirname(os.path.dirname(module.__file__))
    return p


class CombineIncludePaths(argparse.Action):
    """
    Custom action to combine multiple include paths into a set.

    Appends each new include path to the existing set of include paths.
    """
    def __call__(self, parser, namespace, values, option_string=None):
        include_paths_set = set(getattr(namespace, 'include_paths', []) or [])
        if option_string == "--include_paths":
            outmess("Use --include-paths or -I instead of --include_paths which will be removed")
        if option_string == "--include-paths" or option_string == "--include_paths":
            include_paths_set.update(values.split(':'))
        else:
            include_paths_set.add(values)
        setattr(namespace, 'include_paths', list(include_paths_set))


def include_parser():
    """
    Create an ArgumentParser for handling include paths.

    Returns:
    parser: ArgumentParser object configured for include paths.
    """
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument("-I", dest="include_paths", action=CombineIncludePaths)
    parser.add_argument("--include-paths", dest="include_paths", action=CombineIncludePaths)
    parser.add_argument("--include_paths", dest="include_paths", action=CombineIncludePaths)
    return parser


def get_includes(iline):
    """
    Parse a list of command-line arguments to extract include paths.

    iline: list of str, command-line arguments.

    Returns:
    ipaths: list of str, include paths extracted from the command-line.
    remain: list of str, remaining command-line arguments after parsing include paths.
    """
    iline = (' '.join(iline)).split()
    parser = include_parser()
    args, remain = parser.parse_known_args(iline)
    ipaths = args.include_paths
    if args.include_paths is None:
        ipaths = []
    return ipaths, remain


def make_f2py_compile_parser():
    """
    Create an ArgumentParser for parsing f2py compilation options.

    Returns:
    parser: ArgumentParser object configured for f2py compilation options.
    """
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument("--dep", action="append", dest="dependencies")
    parser.add_argument("--backend", choices=['meson', 'distutils'], default='distutils')
    parser.add_argument("-m", dest="module_name")
    return parser


def preparse_sysargv():
    """
    Prepare sys.argv for f2py compilation.

    Parses sys.argv using a predefined parser and adjusts it accordingly.
    """
    # To keep backwards bug compatibility, newer flags are handled by argparse,
    # and `sys.argv` is passed to the rest of `f2py` as is.
    parser = make_f2py_compile_parser()

    args, remaining_argv = parser.parse_known_args()
    sys.argv = [sys.argv[0]] + remaining_argv

    backend_key = args.backend
    if MESON_ONLY_VER and backend_key == 'distutils':
        outmess("Cannot use distutils backend with Python>=3.12,"
                " using meson backend instead.\n")
        backend_key = "meson"

    return {
        "dependencies": args.dependencies or [],
        "backend": backend_key,
        "modulename": args.module_name,
    }


def run_compile():
    """
    Perform all necessary actions for f2py compilation in one function call.

    Collects dependency flags, preprocesses sys.argv, and retrieves the module name.
    """
    import tempfile

    # Collect dependency flags, preprocess sys.argv
    argy = preparse_sysargv()
    modulename = argy["modulename"]
    # 如果模块名为 None,则将其设置为 'untitled'
    if modulename is None:
        modulename = 'untitled'

    # 从 argy 字典中获取依赖项列表
    dependencies = argy["dependencies"]

    # 从 argy 字典中获取后端关键字
    backend_key = argy["backend"]

    # 使用 backend_key 调用 f2py_build_generator 函数,生成构建后端对象
    build_backend = f2py_build_generator(backend_key)

    # 找到并删除命令行参数列表中的 '-c' 参数
    i = sys.argv.index('-c')
    del sys.argv[i]

    # 初始化 remove_build_dir 变量为 0
    remove_build_dir = 0

    # 尝试找到 '--build-dir' 参数在命令行参数列表中的位置
    try:
        i = sys.argv.index('--build-dir')
    except ValueError:
        i = None

    # 根据 '--build-dir' 参数的存在与否,设置 build_dir 和相应的命令行参数
    if i is not None:
        build_dir = sys.argv[i + 1]
        del sys.argv[i + 1]
        del sys.argv[i]
    else:
        # 如果未指定 '--build-dir' 参数,则创建临时目录并设置为 build_dir
        remove_build_dir = 1
        build_dir = tempfile.mkdtemp()

    # 使用正则表达式 _reg1 匹配 '--link-' 开头的参数,存储在 sysinfo_flags 中
    _reg1 = re.compile(r'--link-')
    sysinfo_flags = [_m for _m in sys.argv[1:] if _reg1.match(_m)]

    # 从 sys.argv 中移除 sysinfo_flags 中包含的参数
    sys.argv = [_m for _m in sys.argv if _m not in sysinfo_flags]

    # 如果 sysinfo_flags 不为空,去除每个元素中的 '--link-' 前缀
    if sysinfo_flags:
        sysinfo_flags = [f[7:] for f in sysinfo_flags]

    # 使用正则表达式 _reg2 匹配一系列参数,存储在 f2py_flags 中,并从 sys.argv 中移除它们
    _reg2 = re.compile(
        r'--((no-|)(wrap-functions|lower)|debug-capi|quiet|skip-empty-wrappers)|-include')
    f2py_flags = [_m for _m in sys.argv[1:] if _reg2.match(_m)]
    sys.argv = [_m for _m in sys.argv if _m not in f2py_flags]

    # 初始化 f2py_flags2 和 fl 变量
    f2py_flags2 = []
    fl = 0

    # 遍历 sys.argv 中的每个参数
    for a in sys.argv[1:]:
        # 如果 a 在 ['only:', 'skip:'] 中,则将 fl 设置为 1
        if a in ['only:', 'skip:']:
            fl = 1
        # 如果 a 为 ':', 则将 fl 设置为 0
        elif a == ':':
            fl = 0
        # 如果 fl 为真或者 a 为 ':', 则将 a 添加到 f2py_flags2 列表中
        if fl or a == ':':
            f2py_flags2.append(a)

    # 如果 f2py_flags2 不为空且最后一个元素不是 ':', 则添加 ':'
    if f2py_flags2 and f2py_flags2[-1] != ':':
        f2py_flags2.append(':')

    # 将 f2py_flags2 的内容添加到 f2py_flags 中
    f2py_flags.extend(f2py_flags2)

    # 从 sys.argv 中移除 f2py_flags2 中包含的参数
    sys.argv = [_m for _m in sys.argv if _m not in f2py_flags2]

    # 使用正则表达式 _reg3 匹配一系列参数,存储在 flib_flags 中,并从 sys.argv 中移除它们
    _reg3 = re.compile(
        r'--((f(90)?compiler(-exec|)|compiler)=|help-compiler)')
    flib_flags = [_m for _m in sys.argv[1:] if _reg3.match(_m)]
    sys.argv = [_m for _m in sys.argv if _m not in flib_flags]

    # 定义正则表达式以匹配特定的 f77 和 f90 参数
    reg_f77_f90_flags = re.compile(r'--f(77|90)flags=')
    reg_distutils_flags = re.compile(r'--((f(77|90)exec|opt|arch)=|(debug|noopt|noarch|help-fcompiler))')

    # 从 sys.argv 中筛选出 fc_flags 和 distutils_flags
    fc_flags = [_m for _m in sys.argv[1:] if reg_f77_f90_flags.match(_m)]
    distutils_flags = [_m for _m in sys.argv[1:] if reg_distutils_flags.match(_m)]

    # 如果 MESON_ONLY_VER 为假且 backend_key 不为 'meson',则将 distutils_flags 添加到 fc_flags 中
    if not (MESON_ONLY_VER or backend_key == 'meson'):
        fc_flags.extend(distutils_flags)

    # 从 sys.argv 中移除 fc_flags 和 distutils_flags
    sys.argv = [_m for _m in sys.argv if _m not in (fc_flags + distutils_flags)]

    # 初始化 del_list 列表,用于存储待删除的参数
    del_list = []
    for s in flib_flags:
        # 定义用于识别编译器选项的前缀字符串
        v = '--fcompiler='
        # 如果当前字符串 s 的开头是 v,则进入条件
        if s[:len(v)] == v:
            # 如果 MESON_ONLY_VER 为真或者 backend_key 为 'meson',则输出提示信息
            if MESON_ONLY_VER or backend_key == 'meson':
                outmess(
                    "--fcompiler cannot be used with meson,"
                    "set compiler with the FC environment variable\n"
                    )
            else:
                # 导入 numpy.distutils 中的 fcompiler 模块
                from numpy.distutils import fcompiler
                # 加载所有的编译器类
                fcompiler.load_all_fcompiler_classes()
                # 获取所有已知编译器的键列表
                allowed_keys = list(fcompiler.fcompiler_class.keys())
                # 将 s 后面的部分转换为小写,并赋值给 nv 和 ov
                nv = ov = s[len(v):].lower()
                # 如果 ov 不在允许的键列表中
                if ov not in allowed_keys:
                    vmap = {}  # XXX
                    # 尝试使用 vmap 进行映射转换
                    try:
                        nv = vmap[ov]
                    except KeyError:
                        # 如果 ov 不在 vmap 的值列表中,则打印未知厂商信息
                        if ov not in vmap.values():
                            print('Unknown vendor: "%s"' % (s[len(v):]))
                    # 若没有找到映射,则 nv 保持 ov 不变
                    nv = ov
                # 找到 s 在 flib_flags 中的索引 i
                i = flib_flags.index(s)
                # 更新 flib_flags 中的元素为新的编译器选项
                flib_flags[i] = '--fcompiler=' + nv
                # 继续处理下一个 flib_flags 元素
                continue
    for s in del_list:
        # 找到 s 在 flib_flags 中的索引 i
        i = flib_flags.index(s)
        # 从 flib_flags 中删除该元素
        del flib_flags[i]
    # 断言 flib_flags 的长度不超过 2,用于验证条件
    assert len(flib_flags) <= 2, repr(flib_flags)

    _reg5 = re.compile(r'--(verbose)')
    # 从 sys.argv 中筛选出符合正则表达式 _reg5 的参数,放入 setup_flags
    setup_flags = [_m for _m in sys.argv[1:] if _reg5.match(_m)]
    # 从 sys.argv 中移除 setup_flags 中的参数
    sys.argv = [_m for _m in sys.argv if _m not in setup_flags]

    if '--quiet' in f2py_flags:
        # 如果 '--quiet' 在 f2py_flags 中,则添加到 setup_flags
        setup_flags.append('--quiet')

    # 丑陋的过滤器,用于移除除了源文件外的所有内容
    sources = sys.argv[1:]
    f2cmapopt = '--f2cmap'
    # 如果 f2cmapopt 在 sys.argv 中
    if f2cmapopt in sys.argv:
        # 找到 f2cmapopt 在 sys.argv 中的索引 i
        i = sys.argv.index(f2cmapopt)
        # 将 f2py_flags 扩展为包含 f2cmapopt 及其后续参数
        f2py_flags.extend(sys.argv[i:i + 2])
        # 删除 sys.argv 中的 f2cmapopt 及其后续参数
        del sys.argv[i + 1], sys.argv[i]
        # 更新 sources 为处理后的 sys.argv 中的源文件列表
        sources = sys.argv[1:]

    # 过滤出 pyf 文件和其他源文件
    pyf_files, _sources = filter_files("", "[.]pyf([.]src|)", sources)
    # 合并 pyf_files 和 _sources 到 sources
    sources = pyf_files + _sources
    # 验证模块名是否有效,返回有效的模块名
    modulename = validate_modulename(pyf_files, modulename)
    # 过滤出额外的目标文件和源文件
    extra_objects, sources = filter_files('', '[.](o|a|so|dylib)', sources)
    # 过滤出库目录和源文件
    library_dirs, sources = filter_files('-L', '', sources, remove_prefix=1)
    # 过滤出库名称和源文件
    libraries, sources = filter_files('-l', '', sources, remove_prefix=1)
    # 过滤出未定义的宏和源文件
    undef_macros, sources = filter_files('-U', '', sources, remove_prefix=1)
    # 过滤出定义的宏和源文件
    define_macros, sources = filter_files('-D', '', sources, remove_prefix=1)
    # 遍历所有的定义宏,将形如 name=value 的字符串拆分成元组
    for i in range(len(define_macros)):
        name_value = define_macros[i].split('=', 1)
        # 如果只有名字没有值,则将值设为 None
        if len(name_value) == 1:
            name_value.append(None)
        # 如果有名字和值,则将其作为元组赋值给 define_macros[i]
        if len(name_value) == 2:
            define_macros[i] = tuple(name_value)
        else:
            print('Invalid use of -D:', name_value)

    # 构建包装器、签名或其他所需内容
    if backend_key == 'meson':
        # 如果使用 meson 后端
        if not pyf_files:
            # 如果没有 pyf 文件,则输出使用 meson 后端的信息并设置 f2py_flags
            outmess('Using meson backend\nWill pass --lower to f2py\nSee https://numpy.org/doc/stable/f2py/buildtools/meson.html\n')
            f2py_flags.append('--lower')
            # 运行主函数,传递适当的参数给 f2py
            run_main(f" {' '.join(f2py_flags)} -m {modulename} {' '.join(sources)}".split())
        else:
            # 如果有 pyf 文件,则运行主函数,传递适当的参数给 f2py
            run_main(f" {' '.join(f2py_flags)} {' '.join(pyf_files)}".split())
    # 获取源文件的包含目录和源文件列表,用于后续构建
    include_dirs, sources = get_includes(sources)
    
    # 使用获取到的参数创建后端构建器对象
    builder = build_backend(
        modulename,           # 模块名称
        sources,              # 源文件列表
        extra_objects,        # 额外的对象文件列表
        build_dir,            # 构建目录
        include_dirs,         # 包含目录列表
        library_dirs,         # 库文件目录列表
        libraries,            # 库文件列表
        define_macros,        # 宏定义列表
        undef_macros,         # 宏未定义列表
        f2py_flags,           # f2py 标志
        sysinfo_flags,        # 系统信息标志
        fc_flags,             # fc 标志
        flib_flags,           # flib 标志
        setup_flags,          # 设置标志
        remove_build_dir,     # 是否移除构建目录的标志
        {"dependencies": dependencies},  # 依赖项字典
    )
    
    # 编译构建器对象
    builder.compile()
# 验证模块名称是否有效,可以根据需要重置模块名称
def validate_modulename(pyf_files, modulename='untitled'):
    # 如果传入的 .pyf 文件数量大于1,抛出数值错误异常
    if len(pyf_files) > 1:
        raise ValueError("Only one .pyf file per call")
    
    # 如果有 .pyf 文件
    if pyf_files:
        # 获取第一个 .pyf 文件的路径
        pyff = pyf_files[0]
        # 调用 auxfuncs 模块中的 get_f2py_modulename 函数获取模块名
        pyf_modname = auxfuncs.get_f2py_modulename(pyff)
        
        # 如果指定的模块名与 .pyf 文件中获取的模块名不一致
        if modulename != pyf_modname:
            # 输出警告信息,指出正在忽略指定的模块名,并显示 .pyf 文件中的实际模块名
            outmess(
                f"Ignoring -m {modulename}.\n"
                f"{pyff} defines {pyf_modname} to be the modulename.\n"
            )
            # 使用 .pyf 文件中获取的模块名作为新的模块名
            modulename = pyf_modname
    
    # 返回最终确认的模块名
    return modulename

# 主函数,根据命令行参数执行不同的操作
def main():
    # 如果命令行参数中包含 '--help-link'
    if '--help-link' in sys.argv[1:]:
        # 移除 '--help-link' 参数
        sys.argv.remove('--help-link')
        
        # 如果 MESON_ONLY_VER 为真,输出提示信息告知使用 '--dep' 用于 Meson 构建
        if MESON_ONLY_VER:
            outmess("Use --dep for meson builds\n")
        else:
            # 否则导入 numpy.distutils.system_info 模块,并调用 show_all 函数显示所有系统信息
            from numpy.distutils.system_info import show_all
            show_all()
        
        # 函数返回,结束执行
        return
    
    # 如果命令行参数中包含 '-c'
    if '-c' in sys.argv[1:]:
        # 运行编译函数
        run_compile()
    else:
        # 否则运行主函数,传入剩余的命令行参数(除了程序名以外的参数)
        run_main(sys.argv[1:])

.\numpy\numpy\f2py\f90mod_rules.py

"""
Build F90 module support for f2py2e.

Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.

NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
"""
# 定义版本信息字符串,从 "$Revision: 1.27 $" 提取版本号
__version__ = "$Revision: 1.27 $"[10:-1]

# 定义 f2py_version 字符串
f2py_version = 'See `f2py -v`'

# 导入 NumPy 库,并重命名为 np
import numpy as np

# 从当前包中导入 capi_maps、func2subr、undo_rmbadname、undo_rmbadname1 模块
from . import capi_maps
from . import func2subr
from .crackfortran import undo_rmbadname, undo_rmbadname1

# 从 auxfuncs 模块中导入所有函数和对象
from .auxfuncs import *

# 定义空字典 options
options = {}

# 定义函数 findf90modules,查找模块中的 Fortran 90 模块
def findf90modules(m):
    # 如果 m 是模块,则返回列表包含 m 自身
    if ismodule(m):
        return [m]
    # 如果 m 没有主体或者主体为空,则返回空列表
    if not hasbody(m):
        return []
    ret = []
    # 遍历 m 的主体
    for b in m['body']:
        # 如果 b 是模块,则添加到 ret 列表中
        if ismodule(b):
            ret.append(b)
        else:
            # 否则递归查找 b 中的 Fortran 90 模块并加入 ret 列表
            ret = ret + findf90modules(b)
    return ret

# 定义 fgetdims1 字符串,包含 Fortran 代码片段
fgetdims1 = """\
      external f2pysetdata
      logical ns
      integer r,i
      integer(%d) s(*)
      ns = .FALSE.
      if (allocated(d)) then
         do i=1,r
            if ((size(d,i).ne.s(i)).and.(s(i).ge.0)) then
               ns = .TRUE.
            end if
         end do
         if (ns) then
            deallocate(d)
         end if
      end if
      if ((.not.allocated(d)).and.(s(1).ge.1)) then""" % np.intp().itemsize

# 定义 fgetdims2 字符串,包含 Fortran 代码片段
fgetdims2 = """\
      end if
      if (allocated(d)) then
         do i=1,r
            s(i) = size(d,i)
         end do
      end if
      flag = 1
      call f2pysetdata(d,allocated(d))"""

# 定义 fgetdims2_sa 字符串,包含 Fortran 代码片段
fgetdims2_sa = """\
      end if
      if (allocated(d)) then
         do i=1,r
            s(i) = size(d,i)
         end do
         !s(r) must be equal to len(d(1))
      end if
      flag = 2
      call f2pysetdata(d,allocated(d))"""

# 定义函数 buildhooks,用于构建钩子
def buildhooks(pymod):
    # 从当前包中导入 rules 模块
    from . import rules
    # 定义返回的字典 ret,包含各种钩子和文档
    ret = {'f90modhooks': [], 'initf90modhooks': [], 'body': [],
           'need': ['F_FUNC', 'arrayobject.h'],
           'separatorsfor': {'includes0': '\n', 'includes': '\n'},
           'docs': ['"Fortran 90/95 modules:\\n"'],
           'latexdoc': []}
    # 定义空字符串 fhooks
    fhooks = ['']

    # 定义函数 fadd,用于向 fhooks 添加行
    def fadd(line, s=fhooks):
        s[0] = '%s\n      %s' % (s[0], line)
    
    # 定义空列表 doc
    doc = ['']

    # 定义函数 dadd,用于向 doc 添加行
    def dadd(line, s=doc):
        s[0] = '%s\n%s' % (s[0], line)

    # 使用 getuseblocks 函数获取 pymod 的 use 块信息
    usenames = getuseblocks(pymod)
    
    # 设置 ret 的一些属性为空字符串或空列表
    ret['routine_defs'] = ''
    ret['doc'] = []
    ret['docshort'] = []
    ret['latexdoc'] = doc[0]
    
    # 如果 docs 的长度小于等于 1,则将其设置为空字符串
    if len(ret['docs']) <= 1:
        ret['docs'] = ''
    
    # 返回 ret 和 fhooks 的第一个元素
    return ret, fhooks[0]

.\numpy\numpy\f2py\func2subr.py

"""
Rules for building C/API module with f2py2e.

Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.

NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
"""
# 导入必要的模块
import copy

# 从本地模块中导入辅助函数
from .auxfuncs import (
    getfortranname, isexternal, isfunction, isfunction_wrap, isintent_in,
    isintent_out, islogicalfunction, ismoduleroutine, isscalar,
    issubroutine, issubroutine_wrap, outmess, show
)

# 从_isocbind模块导入isoc_kindmap变量
from ._isocbind import isoc_kindmap

# 将变量映射为适合Fortran的定义
def var2fixfortran(vars, a, fa=None, f90mode=None):
    # 如果fa未指定,则默认为a
    if fa is None:
        fa = a
    # 如果a不在变量字典中,则显示变量列表并输出消息,返回空字符串
    if a not in vars:
        show(vars)
        outmess('var2fixfortran: No definition for argument "%s".\n' % a)
        return ''
    # 如果变量定义中没有类型说明,则显示变量信息并输出消息,返回空字符串
    if 'typespec' not in vars[a]:
        show(vars[a])
        outmess('var2fixfortran: No typespec for argument "%s".\n' % a)
        return ''
    # 获取变量的类型定义
    vardef = vars[a]['typespec']
    # 如果变量类型是'type'并且有typename属性,则在类型定义中添加typename
    if vardef == 'type' and 'typename' in vars[a]:
        vardef = '%s(%s)' % (vardef, vars[a]['typename'])
    selector = {}
    lk = ''
    # 如果变量具有'kindselector'属性,则将其作为kindselector
    if 'kindselector' in vars[a]:
        selector = vars[a]['kindselector']
        lk = 'kind'
    # 如果变量具有'charselector'属性,则将其作为charselector
    elif 'charselector' in vars[a]:
        selector = vars[a]['charselector']
        lk = 'len'
    # 如果selector中包含'*',根据f90mode添加变量定义
    if '*' in selector:
        if f90mode:
            if selector['*'] in ['*', ':', '(*)']:
                vardef = '%s(len=*)' % (vardef)
            else:
                vardef = '%s(%s=%s)' % (vardef, lk, selector['*'])
        else:
            if selector['*'] in ['*', ':']:
                vardef = '%s*(%s)' % (vardef, selector['*'])
            else:
                vardef = '%s*%s' % (vardef, selector['*'])
    else:
        # 如果selector中包含'len'属性,则添加长度限定
        if 'len' in selector:
            vardef = '%s(len=%s' % (vardef, selector['len'])
            if 'kind' in selector:
                vardef = '%s,kind=%s)' % (vardef, selector['kind'])
            else:
                vardef = '%s)' % (vardef)
        # 如果selector中包含'kind'属性,则添加kind属性
        elif 'kind' in selector:
            vardef = '%s(kind=%s)' % (vardef, selector['kind'])

    # 将最终的变量定义与fa连接起来
    vardef = '%s %s' % (vardef, fa)
    # 如果变量具有'dimension'属性,则添加维度信息
    if 'dimension' in vars[a]:
        vardef = '%s(%s)' % (vardef, ','.join(vars[a]['dimension']))
    return vardef

# 检查是否需要使用iso_c_binding模块
def useiso_c_binding(rout):
    useisoc = False
    # 遍历函数变量字典,检查每个变量的kindselector是否在isoc_kindmap中
    for key, value in rout['vars'].items():
        kind_value = value.get('kindselector', {}).get('kind')
        if kind_value in isoc_kindmap:
            return True
    return useisoc

# 创建函数包装器
def createfuncwrapper(rout, signature=0):
    # 断言函数是外部函数
    assert isfunction(rout)

    extra_args = []
    vars = rout['vars']
    # 遍历路由字典中的参数列表
    for a in rout['args']:
        # 获取当前参数在变量字典中的信息
        v = rout['vars'][a]
        # 遍历参数的维度信息,对于每个维度进行处理
        for i, d in enumerate(v.get('dimension', [])):
            # 如果维度标识为冒号,生成新的维度变量名
            if d == ':':
                dn = 'f2py_%s_d%s' % (a, i)
                # 创建新的维度变量字典
                dv = dict(typespec='integer', intent=['hide'])
                dv['='] = 'shape(%s, %s)' % (a, i)
                # 将新的维度变量名添加到额外参数列表
                extra_args.append(dn)
                # 在变量字典中添加新的维度变量信息
                vars[dn] = dv
                # 更新参数的维度信息为新的维度变量名
                v['dimension'][i] = dn

    # 将额外的参数列表添加到路由参数列表末尾
    rout['args'].extend(extra_args)
    # 检查是否需要生成接口
    need_interface = bool(extra_args)

    # 初始化返回结果列表
    ret = ['']

    # 定义用于将行添加到返回结果列表的函数
    def add(line, ret=ret):
        ret[0] = '%s\n      %s' % (ret[0], line)

    # 获取路由的名称
    name = rout['name']
    # 获取路由的 Fortran 名称
    fortranname = getfortranname(rout)
    # 检查是否为模块化路由
    f90mode = ismoduleroutine(rout)
    # 生成新的路由名称
    newname = '%sf2pywrap' % (name)

    # 如果新的路由名称不在变量字典中,则复制原有路由名称的变量信息
    if newname not in vars:
        vars[newname] = vars[name]
        # 更新参数列表,将原有路由名称替换为新的路由名称
        args = [newname] + rout['args'][1:]
    else:
        args = [newname] + rout['args']

    # 将变量字典中的信息转换为固定格式的 Fortran 代码
    l_tmpl = var2fixfortran(vars, name, '@@@NAME@@@', f90mode)
    
    # 如果第一行的类型声明为 character*(*),根据 Fortran 标准设置长度
    if l_tmpl[:13] == 'character*(*)':
        if f90mode:
            l_tmpl = 'character(len=10)' + l_tmpl[13:]
        else:
            l_tmpl = 'character*10' + l_tmpl[13:]
        # 更新字符选择器字典中的信息
        charselect = vars[name]['charselector']
        if charselect.get('*', '') == '(*)':
            charselect['*'] = '10'

    # 将第一行转换为新路由名称的声明
    l1 = l_tmpl.replace('@@@NAME@@@', newname)
    rl = None

    # 检查是否使用 ISO C 绑定
    useisoc = useiso_c_binding(rout)
    # 将参数列表转换为字符串
    sargs = ', '.join(args)
    if f90mode:
        # 修正问题编号为 gh-23598 的警告
        # 重新生成参数列表,移除模块名称和路由名称
        sargs = sargs.replace(f"{name}, ", '')
        args = [arg for arg in args if arg != name]
        # 更新路由参数列表
        rout['args'] = args
        # 添加新的子程序声明到返回结果列表中
        add('subroutine f2pywrap_%s_%s (%s)' %
            (rout['modulename'], name, sargs))
        # 如果没有签名信息,添加模块使用声明到返回结果列表中
        if not signature:
            add('use %s, only : %s' % (rout['modulename'], fortranname))
        # 如果使用 ISO C 绑定,添加使用声明到返回结果列表中
        if useisoc:
            add('use iso_c_binding')
    else:
        # 添加新的子程序声明到返回结果列表中
        add('subroutine f2pywrap%s (%s)' % (name, sargs))
        # 如果使用 ISO C 绑定,添加使用声明到返回结果列表中
        if useisoc:
            add('use iso_c_binding')
        # 如果不需要生成接口,添加外部函数声明到返回结果列表中
        if not need_interface:
            add('external %s' % (fortranname))
            # 生成新的声明语句并赋值给 rl
            rl = l_tmpl.replace('@@@NAME@@@', '') + ' ' + fortranname

    # 如果需要生成接口,处理保存的接口信息
    if need_interface:
        for line in rout['saved_interface'].split('\n'):
            # 添加不包含 '__user__' 的 use 声明到返回结果列表中
            if line.lstrip().startswith('use ') and '__user__' not in line:
                add(line)

    # 更新参数列表,移除第一个参数
    args = args[1:]
    # 初始化已生成参数列表为空
    dumped_args = []
    # 遍历参数列表
    for a in args:
        # 如果变量为外部变量,添加外部声明到返回结果列表中
        if isexternal(vars[a]):
            add('external %s' % (a))
            # 将已处理的参数添加到已生成参数列表中
            dumped_args.append(a)
    # 遍历参数列表
    for a in args:
        # 如果参数已在已生成参数列表中,跳过当前参数
        if a in dumped_args:
            continue
        # 如果变量为标量,添加变量声明到返回结果列表中
        if isscalar(vars[a]):
            add(var2fixfortran(vars, a, f90mode=f90mode))
            # 将已处理的参数添加到已生成参数列表中
            dumped_args.append(a)
    # 遍历参数列表
    for a in args:
        # 如果参数已在已生成参数列表中,跳过当前参数
        if a in dumped_args:
            continue
        # 如果变量为输入参数,添加变量声明到返回结果列表中
        if isintent_in(vars[a]):
            add(var2fixfortran(vars, a, f90mode=f90mode))
            # 将已处理的参数添加到已生成参数列表中
            dumped_args.append(a)
    # 遍历参数列表args中的每个参数a
    for a in args:
        # 如果参数a已经在dumped_args中,则跳过当前循环
        if a in dumped_args:
            continue
        # 调用函数var2fixfortran,并将返回值添加到结果集中
        add(var2fixfortran(vars, a, f90mode=f90mode))

    # 将变量l1添加到结果集中
    add(l1)
    # 如果参数rl不为None,则将其添加到结果集中
    if rl is not None:
        add(rl)

    # 如果需要接口定义
    if need_interface:
        # 如果处于f90模式下
        if f90mode:
            # f90模块已经定义了所需的接口,不需要额外操作
            pass
        else:
            # 添加interface关键字到结果集中
            add('interface')
            # 添加保存的接口内容到结果集中(去掉左侧空格)
            add(rout['saved_interface'].lstrip())
            # 添加end interface到结果集中

            add('end interface')

    # 将args中不在extra_args中的参数用', '连接成字符串
    sargs = ', '.join([a for a in args if a not in extra_args])

    # 如果不需要生成函数签名
    if not signature:
        # 如果rout是逻辑函数
        if islogicalfunction(rout):
            # 生成逻辑函数的赋值语句,添加到结果集中
            add('%s = .not.(.not.%s(%s))' % (newname, fortranname, sargs))
        else:
            # 生成一般函数的调用语句,添加到结果集中
            add('%s = %s(%s)' % (newname, fortranname, sargs))
    
    # 如果处于f90模式下
    if f90mode:
        # 添加f90模式下的子程序结束语句到结果集中
        add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name))
    else:
        # 添加一般的结束语句到结果集中
        add('end')

    # 返回结果集的第一个元素
    return ret[0]
# 定义一个函数,用于创建包装子程序的包装器
def createsubrwrapper(rout, signature=0):

    # 断言rout确实是一个子程序
    assert issubroutine(rout)

    # 用于存储额外参数的列表
    extra_args = []

    # 从rout中获取变量字典
    vars = rout['vars']

    # 遍历rout中的参数
    for a in rout['args']:
        # 获取参数对应的变量
        v = rout['vars'][a]
        # 遍历该变量的维度信息
        for i, d in enumerate(v.get('dimension', [])):
            # 如果维度为':'
            if d == ':':
                # 创建新的维度名
                dn = 'f2py_%s_d%s' % (a, i)
                # 创建维度变量的字典
                dv = dict(typespec='integer', intent=['hide'])
                dv['='] = 'shape(%s, %s)' % (a, i)
                # 添加到额外参数列表中
                extra_args.append(dn)
                # 将维度变量添加到变量字典中
                vars[dn] = dv
                # 更新原始参数的维度信息
                v['dimension'][i] = dn

    # 将额外参数添加到参数列表中
    rout['args'].extend(extra_args)

    # 是否需要接口的标志
    need_interface = bool(extra_args)

    # 初始化返回结果的列表
    ret = ['']

    # 定义一个内部函数,用于将文本行添加到返回结果中
    def add(line, ret=ret):
        ret[0] = '%s\n      %s' % (ret[0], line)

    # 获取子程序的名称
    name = rout['name']

    # 获取子程序的Fortran名称
    fortranname = getfortranname(rout)

    # 检查是否为Fortran 90模式的子程序
    f90mode = ismoduleroutine(rout)

    # 获取子程序的参数列表
    args = rout['args']

    # 检查是否使用ISO_C_BINDING
    useisoc = useiso_c_binding(rout)

    # 将参数列表转换为字符串形式
    sargs = ', '.join(args)

    # 根据Fortran模式不同,添加不同的子程序定义行
    if f90mode:
        add('subroutine f2pywrap_%s_%s (%s)' %
            (rout['modulename'], name, sargs))
        if useisoc:
            add('use iso_c_binding')
        if not signature:
            add('use %s, only : %s' % (rout['modulename'], fortranname))
    else:
        add('subroutine f2pywrap%s (%s)' % (name, sargs))
        if useisoc:
            add('use iso_c_binding')
        if not need_interface:
            add('external %s' % (fortranname))

    # 如果需要接口,添加保存的接口信息
    if need_interface:
        for line in rout['saved_interface'].split('\n'):
            if line.lstrip().startswith('use ') and '__user__' not in line:
                add(line)

    # 已导出的参数列表
    dumped_args = []

    # 遍历参数列表,如果是外部变量,则添加external声明
    for a in args:
        if isexternal(vars[a]):
            add('external %s' % (a))
            dumped_args.append(a)

    # 继续遍历参数列表,如果是标量,则添加到返回结果中
    for a in args:
        if a in dumped_args:
            continue
        if isscalar(vars[a]):
            add(var2fixfortran(vars, a, f90mode=f90mode))
            dumped_args.append(a)

    # 最后一次遍历参数列表,将变量添加到返回结果中
    for a in args:
        if a in dumped_args:
            continue
        add(var2fixfortran(vars, a, f90mode=f90mode))

    # 如果需要接口,根据Fortran模式添加接口声明
    if need_interface:
        if f90mode:
            # 对于Fortran 90模式,接口已经定义,不需要再次声明
            pass
        else:
            # 添加接口声明
            add('interface')
            for line in rout['saved_interface'].split('\n'):
                if line.lstrip().startswith('use ') and '__user__' in line:
                    continue
                add(line)
            add('end interface')

    # 更新参数列表字符串形式,排除额外参数
    sargs = ', '.join([a for a in args if a not in extra_args])

    # 如果不是签名模式,添加调用Fortran子程序的行
    if not signature:
        add('call %s(%s)' % (fortranname, sargs))

    # 根据Fortran模式添加结束子程序的行
    if f90mode:
        add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name))
    else:
        add('end')

    # 返回处理后的文本结果
    return ret[0]
    # 如果是函数包装,则执行以下代码
    if isfunction_wrap(rout):
        # 获取 Fortran 函数名称
        fortranname = getfortranname(rout)
        # 获取函数名
        name = rout['name']
        # 输出提示信息
        outmess('\t\tCreating wrapper for Fortran function "%s"("%s")...\n' % (
            name, fortranname))
        # 复制函数对象
        rout = copy.copy(rout)
        # 获取函数名
        fname = name
        rname = fname
        # 如果函数对象中有'result'属性,则将其赋值给rname
        if 'result' in rout:
            rname = rout['result']
            rout['vars'][fname] = rout['vars'][rname]
        # 获取函数变量
        fvar = rout['vars'][fname]
        # 如果函数变量不是输出变量,则将其设为输出变量
        if not isintent_out(fvar):
            if 'intent' not in fvar:
                fvar['intent'] = []
            fvar['intent'].append('out')
            flag = 1
            for i in fvar['intent']:
                if i.startswith('out='):
                    flag = 0
                    break
            if flag:
                fvar['intent'].append('out=%s' % (rname))
        # 将函数名添加到参数列表的最前面
        rout['args'][:] = [fname] + rout['args']
        # 返回函数对象和创建的函数包装器
        return rout, createfuncwrapper(rout)
    # 如果是子例程包装,则执行以下代码
    if issubroutine_wrap(rout):
        # 获取 Fortran 子例程名称
        fortranname = getfortranname(rout)
        # 获取子例程名
        name = rout['name']
        # 输出提示信息
        outmess('\t\tCreating wrapper for Fortran subroutine "%s"("%s")...\n'
                % (name, fortranname))
        # 复制子例程对象
        rout = copy.copy(rout)
        # 返回子例程对象和创建的子例程包装器
        return rout, createsubrwrapper(rout)
    # 返回原始对象和空字符串
    return rout, ''

.\numpy\numpy\f2py\rules.py

# 指定脚本的解释器为 Python 3
#!/usr/bin/env python3

"""
Rules for building C/API module with f2py2e.

Here is a skeleton of a new wrapper function (13Dec2001):

wrapper_function(args)
  declarations
  get_python_arguments, say, `a' and `b'

  get_a_from_python
  if (successful) {

    get_b_from_python
    if (successful) {

      callfortran
      if (successful) {

        put_a_to_python
        if (successful) {

          put_b_to_python
          if (successful) {

            buildvalue = ...

          }

        }

      }

    }
    cleanup_b

  }
  cleanup_a

  return buildvalue

Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.

NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
"""

# 导入标准库模块
import os, sys
# 导入时间模块
import time
# 导入拷贝模块
import copy
# 从 pathlib 模块中导入 Path 类
from pathlib import Path

# 导入当前包的版本信息
from . import __version__

# 导入辅助函数
from .auxfuncs import (
    applyrules, debugcapi, dictappend, errmess, gentitle, getargs2,
    hascallstatement, hasexternals, hasinitvalue, hasnote,
    hasresultnote, isarray, isarrayofstrings, ischaracter,
    ischaracterarray, ischaracter_or_characterarray, iscomplex,
    iscomplexarray, iscomplexfunction, iscomplexfunction_warn,
    isdummyroutine, isexternal, isfunction, isfunction_wrap, isint1,
    isint1array, isintent_aux, isintent_c, isintent_callback,
    isintent_copy, isintent_hide, isintent_inout, isintent_nothide,
    isintent_out, isintent_overwrite, islogical, islong_complex,
    islong_double, islong_doublefunction, islong_long,
    islong_longfunction, ismoduleroutine, isoptional, isrequired,
    isscalar, issigned_long_longarray, isstring, isstringarray,
    isstringfunction, issubroutine, isattr_value,
    issubroutine_wrap, isthreadsafe, isunsigned, isunsigned_char,
    isunsigned_chararray, isunsigned_long_long,
    isunsigned_long_longarray, isunsigned_short, isunsigned_shortarray,
    l_and, l_not, l_or, outmess, replace, stripcomma, requiresf90wrapper
)

# 导入包内部模块
from . import capi_maps
from . import cfuncs
from . import common_rules
from . import use_rules
from . import f90mod_rules
from . import func2subr

# 设置 f2py_version 和 numpy_version 变量为当前包的版本信息
f2py_version = __version__.version
numpy_version = __version__.version

# 初始化选项和分隔字典
options = {}
sepdict = {}

# 配置分隔字典的各个键对应的分隔符
for k in ['decl',
          'frompyobj',
          'cleanupfrompyobj',
          'topyarr', 'method',
          'pyobjfrom', 'closepyobjfrom',
          'freemem',
          'userincludes',
          'includes0', 'includes', 'typedefs', 'typedefs_generated',
          'cppmacros', 'cfuncs', 'callbacks',
          'latexdoc',
          'restdoc',
          'routine_defs', 'externroutines',
          'initf2pywraphooks',
          'commonhooks', 'initcommonhooks',
          'f90modhooks', 'initf90modhooks']:
    sepdict[k] = '\n'

# 注释结束,下面是关于 C/API 模块的规则
#################### Rules for C/API module #################
# 获取环境变量中名为 'SOURCE_DATE_EPOCH' 的值,转换为整数,如果不存在则使用当前时间戳
generationtime = int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))

# 定义模块规则字典,包含自动生成的模块文件头部信息
module_rules = {
    # 模块主体部分的注释,包含生成的日期和警告信息
    'modulebody': """\
/* File: #modulename#module.c
 * This file is auto-generated with f2py (version:#f2py_version#).
 * f2py is a Fortran to Python Interface Generator (FPIG), Second Edition,
 * written by Pearu Peterson <pearu@cens.ioc.ee>.
 * Generation date: """ + time.asctime(time.gmtime(generationtime)) + """
 * Do not edit this file directly unless you know what you are doing!!!
 */

#ifdef __cplusplus
extern \"C\" {
#endif

#ifndef PY_SSIZE_T_CLEAN
#define PY_SSIZE_T_CLEAN
#endif /* PY_SSIZE_T_CLEAN */

/* Unconditionally included */
#include <Python.h>
#include <numpy/npy_os.h>

""" + gentitle("See f2py2e/cfuncs.py: includes") + """
#includes#
#includes0#

""" + gentitle("See f2py2e/rules.py: mod_rules['modulebody']") + """
static PyObject *#modulename#_error;
static PyObject *#modulename#_module;

""" + gentitle("See f2py2e/cfuncs.py: typedefs") + """
#typedefs#

""" + gentitle("See f2py2e/cfuncs.py: typedefs_generated") + """
#typedefs_generated#

""" + gentitle("See f2py2e/cfuncs.py: cppmacros") + """
#cppmacros#

""" + gentitle("See f2py2e/cfuncs.py: cfuncs") + """
#cfuncs#

""" + gentitle("See f2py2e/cfuncs.py: userincludes") + """
#userincludes#

""" + gentitle("See f2py2e/capi_rules.py: usercode") + """
#usercode#

/* See f2py2e/rules.py */
#externroutines#

""" + gentitle("See f2py2e/capi_rules.py: usercode1") + """
#usercode1#

""" + gentitle("See f2py2e/cb_rules.py: buildcallback") + """
#callbacks#

""" + gentitle("See f2py2e/rules.py: buildapi") + """
#body#

""" + gentitle("See f2py2e/f90mod_rules.py: buildhooks") + """
#f90modhooks#

""" + gentitle("See f2py2e/rules.py: module_rules['modulebody']") + """

""" + gentitle("See f2py2e/common_rules.py: buildhooks") + """
#commonhooks#

""" + gentitle("See f2py2e/rules.py") + """

static FortranDataDef f2py_routine_defs[] = {
#routine_defs#
    {NULL}
};

static PyMethodDef f2py_module_methods[] = {
#pymethoddef#
    {NULL,NULL}
};

static struct PyModuleDef moduledef = {
    PyModuleDef_HEAD_INIT,
    "#modulename#",
    NULL,
    -1,
    f2py_module_methods,
    NULL,
    NULL,
    NULL,
    NULL
};

PyMODINIT_FUNC PyInit_#modulename#(void) {
    int i;
    PyObject *m,*d, *s, *tmp;
    m = #modulename#_module = PyModule_Create(&moduledef);
    Py_SET_TYPE(&PyFortran_Type, &PyType_Type);
    import_array();
    if (PyErr_Occurred())
        {PyErr_SetString(PyExc_ImportError, \"can't initialize module #modulename# (failed to import numpy)\"); return m;}
    d = PyModule_GetDict(m);
    s = PyUnicode_FromString(\"#f2py_version#\");
    PyDict_SetItemString(d, \"__version__\", s);
    Py_DECREF(s);
    s = PyUnicode_FromString(
        \"This module '#modulename#' is auto-generated with f2py (version:#f2py_version#).\\nFunctions:\\n\"\n#docs#\".\");
    PyDict_SetItemString(d, \"__doc__\", s);
    Py_DECREF(s);
    s = PyUnicode_FromString(\"""" + numpy_version + """\");
    # 将字符串键为 "__f2py_numpy_version__" 的项设置为变量 s 所指向的对象
    PyDict_SetItemString(d, "__f2py_numpy_version__", s);
    # 递减引用计数,释放对象 s
    Py_DECREF(s);
    #modulename#_error = PyErr_NewException ("#modulename#.error", NULL, NULL);
    /*
     * 将错误对象 #modulename#_error 存储在字典 d 中,以便它可以被释放。
     * 在实践中,这是一个模块,所以它可能不会也不应该被释放。
     */
    PyDict_SetItemString(d, "_#modulename#_error", #modulename#_error);
    # 递减引用计数,释放对象 #modulename#_error
    Py_DECREF(#modulename#_error);
    for(i=0;f2py_routine_defs[i].name!=NULL;i++) {
        // 为 f2py_routine_defs 数组中每个函数定义创建一个 PyFortranObject 对象,并作为属性存储在 tmp 中
        tmp = PyFortranObject_NewAsAttr(&f2py_routine_defs[i]);
        // 将 tmp 对象添加到字典 d 中,键为 f2py_routine_defs[i].name
        PyDict_SetItemString(d, f2py_routine_defs[i].name, tmp);
        // 递减引用计数,释放 tmp 对象
        Py_DECREF(tmp);
    }
# 初始化F2PY包装钩子
defmod_rules = [
    {
        'body': '/*eof body*/',  # 模块主体结束标志
        'method': '/*eof method*/',  # 方法结束标志
        'externroutines': '/*eof externroutines*/',  # 外部函数声明结束标志
        'routine_defs': '/*eof routine_defs*/',  # 函数定义结束标志
        'initf90modhooks': '/*eof initf90modhooks*/',  # 初始化F90模块钩子结束标志
        'initf2pywraphooks': '/*eof initf2pywraphooks*/',  # 初始化F2PY包装钩子结束标志
        'initcommonhooks': '/*eof initcommonhooks*/',  # 初始化公共钩子结束标志
        'latexdoc': '',  # LaTeX文档内容为空
        'restdoc': '',  # reStructuredText文档内容为空
        'modnote': {hasnote: '#note#', l_not(hasnote): ''},  # 模块注释存在与不存在的情况分别为“#note#”和空字符串
    }
]

routine_rules = {
    'separatorsfor': sepdict,  # 用于分隔符的字典
    'body': """
#begintitle#
static char doc_#apiname#[] = \"\\\n#docreturn##name#(#docsignatureshort#)\\n\\nWrapper for ``#name#``.\\\n\\n#docstrsigns#\";
/* #declfortranroutine# */
static PyObject *#apiname#(const PyObject *capi_self,
                           PyObject *capi_args,
                           PyObject *capi_keywds,
                           #functype# (*f2py_func)(#callprotoargument#)) {
    PyObject * volatile capi_buildvalue = NULL;
    volatile int f2py_success = 1;
#decl#
    static char *capi_kwlist[] = {#kwlist##kwlistopt##kwlistxa#NULL};
#usercode#
#routdebugenter#
#ifdef F2PY_REPORT_ATEXIT
f2py_start_clock();
#endif
    if (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,\\
        \"#argformat#|#keyformat##xaformat#:#pyname#\",\\
        capi_kwlist#args_capi##keys_capi##keys_xa#))\n        return NULL;
#frompyobj#
/*end of frompyobj*/
#ifdef F2PY_REPORT_ATEXIT
f2py_start_call_clock();
#endif
#callfortranroutine#
if (PyErr_Occurred())
  f2py_success = 0;
#ifdef F2PY_REPORT_ATEXIT
f2py_stop_call_clock();
#endif
/*end of callfortranroutine*/
        if (f2py_success) {
#pyobjfrom#
/*end of pyobjfrom*/
        CFUNCSMESS(\"Building return value.\\n\");
        capi_buildvalue = Py_BuildValue(\"#returnformat#\"#return#);
/*closepyobjfrom*/
#closepyobjfrom#
        } /*if (f2py_success) after callfortranroutine*/
/*cleanupfrompyobj*/
#cleanupfrompyobj#
    if (capi_buildvalue == NULL) {
#routdebugfailure#
    } else {
#routdebugleave#
    }
    CFUNCSMESS(\"Freeing memory.\\n\");
#freemem#
#ifdef F2PY_REPORT_ATEXIT
f2py_stop_clock();
#endif
    return capi_buildvalue;
}
#endtitle#
""",
    'routine_defs': '#routine_def#',  # 函数定义
    'initf2pywraphooks': '#initf2pywraphook#',  # 初始化F2PY包装钩子
    'externroutines': '#declfortranroutine#',  # 外部函数声明
    'doc': '#docreturn##name#(#docsignature#)',  # 文档
    'docshort': '#docreturn##name#(#docsignatureshort#)',  # 简短文档
    'docs': '"    #docreturn##name#(#docsignature#)\\n"\n',  # 文档字符串
}
    # 定义一个字典,包含需要的文件名列表
    'need': ['arrayobject.h', 'CFUNCSMESS', 'MINMAX'],
    # 定义一个字典,包含 C++ 宏的名称及其对应的宏定义
    'cppmacros': {debugcapi: '#define DEBUGCFUNCS'},
    # 定义一个列表,包含 LaTeX 文档中的特定文本内容
    'latexdoc': ['\\subsection{Wrapper function \\texttt{#texname#}}\n',
                 """
                 # 此处可能包含更多的 LaTeX 文档内容,未在示例中显示完整
                 """
                 """
# 定义文档字符串和注释相关的字符串常量和模板
# 注意:这些字符串是用于生成函数文档和注释的模板

# 定义函数的规则和参数配置
rout_rules = [
    {  # Init
        # 指定不同类型的分隔符,用于各种函数和调试信息的分隔
        'separatorsfor': {
            'callfortranroutine': '\n',
            'routdebugenter': '\n',
            'decl': '\n',
            'routdebugleave': '\n',
            'routdebugfailure': '\n',
            'setjmpbuf': ' || ',
            'docstrreq': '\n',
            'docstropt': '\n',
            'docstrout': '\n',
            'docstrcbs': '\n',
            'docstrsigns': '\\n"\n"',
            'latexdocstrsigns': '\n',
            'latexdocstrreq': '\n',
            'latexdocstropt': '\n',
            'latexdocstrout': '\n',
            'latexdocstrcbs': '\n',
        },
        'kwlist': '',
        'kwlistopt': '',
        'callfortran': '',
        'callfortranappend': '',
        'docsign': '',
        'docsignopt': '',
        'decl': '/*decl*/',  # 在声明时添加注释
        'freemem': '/*freemem*/',  # 释放内存时添加注释
        'docsignshort': '',
        'docsignoptshort': '',
        'docstrsigns': '',  # 文档字符串中的标志
        'latexdocstrsigns': '',
        'docstrreq': '\\nParameters\\n----------',  # 必需参数的文档字符串格式
        'docstropt': '\\nOther Parameters\\n----------------',  # 可选参数的文档字符串格式
        'docstrout': '\\nReturns\\n-------',  # 返回值的文档字符串格式
        'docstrcbs': '\\nNotes\\n-----\\nCall-back functions::\\n',  # 回调函数的文档字符串格式
        'latexdocstrreq': '\\noindent Required arguments:',  # LaTeX 格式下的必需参数说明
        'latexdocstropt': '\\noindent Optional arguments:',  # LaTeX 格式下的可选参数说明
        'latexdocstrout': '\\noindent Return objects:',  # LaTeX 格式下的返回对象说明
        'latexdocstrcbs': '\\noindent Call-back functions:',  # LaTeX 格式下的回调函数说明
        'args_capi': '',
        'keys_capi': '',
        'functype': '',
        'frompyobj': '/*frompyobj*/',  # 从 Python 对象转换时的注释
        'cleanupfrompyobj': ['/*end of cleanupfrompyobj*/'],  # 清理从 Python 对象转换的结尾注释
        'pyobjfrom': '/*pyobjfrom*/',  # 转换为 Python 对象时的注释
        'closepyobjfrom': ['/*end of closepyobjfrom*/'],  # 关闭 Python 对象转换时的结尾注释
        'topyarr': '/*topyarr*/',  # 转换为数组时的注释
        'routdebugleave': '/*routdebugleave*/',  # 函数调试离开时的注释
        'routdebugenter': '/*routdebugenter*/',  # 函数调试进入时的注释
        'routdebugfailure': '/*routdebugfailure*/',  # 函数调试失败时的注释
        'callfortranroutine': '/*callfortranroutine*/',  # 调用 Fortran 程序时的注释
        'argformat': '',
        'keyformat': '',
        'need_cfuncs': '',
        'docreturn': '',  # 文档返回值
        'return': '',  # 返回值
        'returnformat': '',
        'rformat': '',
        'kwlistxa': '',
        'keys_xa': '',
        'xaformat': '',
        'docsignxa': '',
        'docsignxashort': '',
        'initf2pywraphook': '',
        'routnote': {hasnote: '--- #note#', l_not(hasnote): ''},  # 函数的注释和说明
    },
    {
        'apiname': 'f2py_rout_#modulename#_#name#',  # 函数 API 名称
        'pyname': '#modulename#.#name#',  # Python 函数名称
        'decl': '',
        '_check': l_not(ismoduleroutine),  # 是否为模块化的函数
    },
    {
        'apiname': 'f2py_rout_#modulename#_#f90modulename#_#name#',  # 函数 API 名称
        'pyname': '#modulename#.#f90modulename#.#name#',  # Python 函数名称
        'decl': '',
        '_check': ismoduleroutine,  # 是否为模块化的函数
    }
]
    }, {  # Subroutine
        'functype': 'void',
        'declfortranroutine': {l_and(l_not(l_or(ismoduleroutine, isintent_c)), l_not(isdummyroutine)): 'extern void #F_FUNC#(#fortranname#,#FORTRANNAME#)(#callprotoargument#);',
                               l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)): 'extern void #fortranname#(#callprotoargument#);',
                               ismoduleroutine: '',  # 如果是模块中的例行程序,不需要任何声明
                               isdummyroutine: ''  # 如果是虚拟例行程序,也不需要任何声明
                               },
        'routine_def': {
            l_not(l_or(ismoduleroutine, isintent_c, isdummyroutine)):
            '    {\"#name#\",-1,{{-1}},0,0,(char *)'
            '  #F_FUNC#(#fortranname#,#FORTRANNAME#),'
            '  (f2py_init_func)#apiname#,doc_#apiname#},',  # 定义非模块例行程序的例行程序的初始化结构体
            l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)):
            '    {\"#name#\",-1,{{-1}},0,0,(char *)#fortranname#,'
            '  (f2py_init_func)#apiname#,doc_#apiname#},',  # 定义 C 意图的例行程序的初始化结构体
            l_and(l_not(ismoduleroutine), isdummyroutine):
            '    {\"#name#\",-1,{{-1}},0,0,NULL,'
            '  (f2py_init_func)#apiname#,doc_#apiname#},',  # 定义虚拟例行程序的初始化结构体
        },
        'need': {l_and(l_not(l_or(ismoduleroutine, isintent_c)), l_not(isdummyroutine)): 'F_FUNC'},  # 非模块例行程序需要 F_FUNC
        'callfortranroutine': [
            {debugcapi: [
                """    fprintf(stderr,\"debug-capi:Fortran subroutine `#fortranname#(#callfortran#)\'\\n\");"""]},  # 如果是 debugcapi,则输出调试信息
            {hasexternals: """\
        if (#setjmpbuf#) {
            f2py_success = 0;
        } else {"""},  # 如果有 externals,则进行异常处理
            {isthreadsafe: '            Py_BEGIN_ALLOW_THREADS'},  # 如果是线程安全的,则开始 Python GIL 保护
            {hascallstatement: '''                #callstatement#;
                /*(*f2py_func)(#callfortran#);*/'''},  # 如果有调用语句,则执行调用
            {l_not(l_or(hascallstatement, isdummyroutine))
                   : '                (*f2py_func)(#callfortran#);'},  # 如果没有调用语句,但不是虚拟例行程序,则执行函数调用
            {isthreadsafe: '            Py_END_ALLOW_THREADS'},  # 结束 Python GIL 保护
            {hasexternals: """        }"""}  # 结束 externals 的异常处理
        ],
        '_check': l_and(issubroutine, l_not(issubroutine_wrap)),  # 检查是否为例行程序,且不是包装过的例行程序
    }, {  # Wrapped function
        'functype': 'void',
        'declfortranroutine': {l_not(l_or(ismoduleroutine, isdummyroutine)): 'extern void #F_WRAPPEDFUNC#(#name_lower#,#NAME#)(#callprotoargument#);',
                               isdummyroutine: ''  # 如果是虚拟例行程序,则不需要声明
                               },

        'routine_def': {
            l_not(l_or(ismoduleroutine, isdummyroutine)):
            '    {\"#name#\",-1,{{-1}},0,0,(char *)'
            '  #F_WRAPPEDFUNC#(#name_lower#,#NAME#),'
            '  (f2py_init_func)#apiname#,doc_#apiname#},',  # 定义非模块虚拟例行程序的初始化结构体
            isdummyroutine:
            '    {\"#name#\",-1,{{-1}},0,0,NULL,'
            '  (f2py_init_func)#apiname#,doc_#apiname#},',  # 定义虚拟例行程序的初始化结构体
        },
        'initf2pywraphook': {l_not(l_or(ismoduleroutine, isdummyroutine)): '''
    {
      // 声明一个外部 C 函数原型,其返回类型为 ctype,函数名为 F_FUNC,参数为 name_lower 和 NAME
      extern #ctype# #F_FUNC#(#name_lower#,#NAME#)(void);
      // 从 Python 字典 d 中获取键名为 "#name#" 的项,并赋给 PyObject 指针 o
      PyObject* o = PyDict_GetItemString(d,"#name#");
      // 使用 F2PyCapsule_FromVoidPtr 函数将 #F_FUNC#(#name_lower#,#NAME#) 的返回值转换为 Python capsule 对象 tmp
      tmp = F2PyCapsule_FromVoidPtr((void*)#F_FUNC#(#name_lower#,#NAME#),NULL);
      // 将 tmp 设置为 o 对象的 "_cpointer" 属性
      PyObject_SetAttrString(o,"_cpointer", tmp);
      // 释放 tmp 对象的引用计数
      Py_DECREF(tmp);
      // 创建字符串对象 s,内容为 "#name#",并赋给 s
      s = PyUnicode_FromString("#name#");
      // 将 s 设置为 o 对象的 "__name__" 属性
      PyObject_SetAttrString(o,"__name__", s);
      // 释放 s 对象的引用计数
      Py_DECREF(s);
    }
    '''},
        // 当 l_not(l_or(ismoduleroutine, isdummyroutine)) 不成立时,需包含 'F_WRAPPEDFUNC''F_FUNC' 两个字段
        'need': {l_not(l_or(ismoduleroutine, isdummyroutine)): ['F_WRAPPEDFUNC', 'F_FUNC']},
        // 若 debugcapi 为真,则输出格式化的调试信息到标准错误流 stderr
        'callfortranroutine': [
            {debugcapi: [
                """    fprintf(stderr,\"debug-capi:Fortran subroutine `f2pywrap#name_lower#(#callfortran#)\'\\n\");"""]},
            // 若 hasexternals 为真,则根据条件设置 f2py_success 的值
            {hasexternals: """\
    if (#setjmpbuf#) {
        f2py_success = 0;
    } else {"""},
            // 若 isthreadsafe 为真,则开始允许 Python 线程
            {isthreadsafe: '    Py_BEGIN_ALLOW_THREADS'},
            // 若 l_not(l_or(hascallstatement, isdummyroutine)) 不成立时,调用指针 f2py_func 指向的函数 #callfortran#
            {l_not(l_or(hascallstatement, isdummyroutine))
                   : '    (*f2py_func)(#callfortran#);'},
            // 若 hascallstatement 为真时,执行 #callstatement# 语句
            {hascallstatement:
                '    #callstatement#;\n    /*(*f2py_func)(#callfortran#);*/'},
            // 若 isthreadsafe 为真,则结束允许 Python 线程
            {isthreadsafe: '    Py_END_ALLOW_THREADS'},
            // 若 hasexternals 为真时,结束条件分支
            {hasexternals: '    }'}
        ],
        // 检查对象是否为函数包装
        '_check': isfunction_wrap,
    }, {  // Wrapped subroutine
        // 函数类型为 void
        'functype': 'void',
        // 定义 Fortran 子例程声明,根据条件设置不同的值
        'declfortranroutine': {l_not(l_or(ismoduleroutine, isdummyroutine)): 'extern void #F_WRAPPEDFUNC#(#name_lower#,#NAME#)(#callprotoargument#);',
                               isdummyroutine: '',
                               },
        // Fortran 子例程定义,根据条件设置不同的值
        'routine_def': {
            l_not(l_or(ismoduleroutine, isdummyroutine)):
            '    {\"#name#\",-1,{{-1}},0,0,(char *)'
            '  #F_WRAPPEDFUNC#(#name_lower#,#NAME#),'
            '  (f2py_init_func)#apiname#,doc_#apiname#},',
            isdummyroutine:
            '    {\"#name#\",-1,{{-1}},0,0,NULL,'
            '  (f2py_init_func)#apiname#,doc_#apiname#},',
        },
        // 初始化 F2Py 包装钩子,根据条件设置不同的值
        'initf2pywraphook': {l_not(l_or(ismoduleroutine, isdummyroutine)): '''
    {
      // 声明一个外部函数原型 #F_FUNC#,其返回类型为 void,参数为 #name_lower# 和 #NAME#
      extern void #F_FUNC#(#name_lower#,#NAME#)(void);
      // 从 Python 字典 d 中获取键名为 "#name#" 的项,并赋给 PyObject 指针 o
      PyObject* o = PyDict_GetItemString(d,"#name#");
      // 使用 F2PyCapsule_FromVoidPtr 函数将 #F_FUNC#(#name_lower#,#NAME#) 的返回值转换为 Python capsule 对象 tmp
      tmp = F2PyCapsule_FromVoidPtr((void*)#F_FUNC#(#name_lower#,#NAME#),NULL);
      // 将 tmp 设置为 o 对象的 "_cpointer" 属性
      PyObject_SetAttrString(o,"_cpointer", tmp);
      // 释放 tmp 对象的引用计数
      Py_DECREF(tmp);
      // 创建字符串对象 s,内容为 "#name#",并赋给 s
      s = PyUnicode_FromString("#name#");
      // 将 s 设置为 o 对象的 "__name__" 属性
      PyObject_SetAttrString(o,"__name__", s);
      // 释放 s 对象的引用计数
      Py_DECREF(s);
    }
    '''},
        // 当 l_not(l_or(ismoduleroutine, isdummyroutine)) 不成立时,需包含 'F_WRAPPEDFUNC''F_FUNC' 两个字段
        'need': {l_not(l_or(ismoduleroutine, isdummyroutine)): ['F_WRAPPEDFUNC', 'F_FUNC']},
        // 调用 Fortran 子例程,根据条件设置不同的值
        'callfortranroutine': [
            // 若 debugcapi 为真,则输出格式化的调试信息到标准错误流 stderr
            {debugcapi: [
                """    fprintf(stderr,\"debug-capi:Fortran subroutine `f2pywrap#name_lower#(#callfortran#)\'\\n\");"""]},
            // 若 hasexternals 为真,则根据条件设置 f2py_success 的值
            {hasexternals: """\
    if (#setjmpbuf#) {
        f2py_success = 0;
    } else {"""},
            // 若 isthreadsafe 为真,则开始允许 Python 线程
            {isthreadsafe: '    Py_BEGIN_ALLOW_THREADS'},
            // 若 l_not(l_or(hascallstatement, isdummyroutine)) 不成立时,调用指针 f2py_func 指向的函数 #callfortran#
            {l_not(l_or(hascallstatement, isdummyroutine))
                   : '    (*f2py_func)(#callfortran#);'},
            // 若 hascallstatement 为真时,执行 #callstatement# 语句
            {hascallstatement:
                '    #callstatement#;\n    /*(*f2py_func)(#callfortran#);*/'},
            // 若 isthreadsafe 为真,则结束允许 Python 线程
            {isthreadsafe: '    Py_END_ALLOW_THREADS'},
            // 若 hasexternals 为真时,结束条件分支
            {hasexternals: '    }'}
        ],
        // 检查对象是否为函数包装
        '_check': isfunction_wrap,
    }
    } else {"""
            # 如果不是线程安全的情况下,进行特定处理
            {isthreadsafe: '    Py_BEGIN_ALLOW_THREADS'},
            # 如果不是调用语句或者是虚拟例程,调用Fortran函数
            {l_not(l_or(hascallstatement, isdummyroutine))
                   : '    (*f2py_func)(#callfortran#);'},
            # 如果有调用语句,执行调用语句并注释掉调用Fortran函数
            {hascallstatement:
                '    #callstatement#;\n    /*(*f2py_func)(#callfortran#);*/'},
            # 如果是线程安全的情况下,结束线程保护区域
            {isthreadsafe: '    Py_END_ALLOW_THREADS'},
            # 如果有外部引用,进行特定处理
            {hasexternals: '    }'}
        ],
        '_check': issubroutine_wrap,
    }, {  # Function
        'functype': '#ctype#',
        'docreturn': {l_not(isintent_hide): '#rname#,'},
        'docstrout': '#pydocsignout#',
        'latexdocstrout': ['\\item[]{{}\\verb@#pydocsignout#@{}}',
                           {hasresultnote: '--- #resultnote#'}],
        'callfortranroutine': [{l_and(debugcapi, isstringfunction): """\
#ifdef USESCOMPAQFORTRAN
    // 如果定义了 USESCOMPAQFORTRAN 宏,则打印使用 Compaq Fortran 的调试信息
    fprintf(stderr,"debug-capi:Fortran function #ctype# #fortranname#(#callcompaqfortran#)\n");
#else
    // 否则,打印使用普通 Fortran 的调试信息
    fprintf(stderr,"debug-capi:Fortran function #ctype# #fortranname#(#callfortran#)\n");
#endif
        '''},
            {l_not(l_or(hascallstatement, isdummyroutine))
                   : '    #name#_return_value = (*f2py_func)(#callfortran#);'},
            {isthreadsafe: '    Py_END_ALLOW_THREADS'},
            {hasexternals: '    }'},
            {l_and(debugcapi, iscomplexfunction)
                   : '    fprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value.r,#name#_return_value.i);'},
            {l_and(debugcapi, l_not(iscomplexfunction)): '    fprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value);'}],
        'pyobjfrom': {iscomplexfunction: '    #name#_return_value_capi = pyobj_from_#ctype#1(#name#_return_value);'},
        'need': [{l_not(isdummyroutine): 'F_FUNC'},
                 {iscomplexfunction: 'pyobj_from_#ctype#1'},
                 {islong_longfunction: 'long_long'},
                 {islong_doublefunction: 'long_double'}],
        'returnformat': {l_not(isintent_hide): '#rformat#'},
        'return': {iscomplexfunction: ',#name#_return_value_capi',
                   l_not(l_or(iscomplexfunction, isintent_hide)): ',#name#_return_value'},
        '_check': l_and(isfunction, l_not(isstringfunction), l_not(isfunction_wrap))
    }, {  # String function # in use for --no-wrap
        'declfortranroutine': 'extern void #F_FUNC#(#fortranname#,#FORTRANNAME#)(#callprotoargument#);',
        'routine_def': {l_not(l_or(ismoduleroutine, isintent_c)):
                        '    {\"#name#\",-1,{{-1}},0,0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},',
                        l_and(l_not(ismoduleroutine), isintent_c):
                        '    {\"#name#\",-1,{{-1}},0,0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},'
                        },
        'decl': ['    #ctype# #name#_return_value = NULL;',  # 声明返回值变量
                 '    int #name#_return_value_len = 0;'],  # 声明返回值长度变量
        'callfortran':'#name#_return_value,#name#_return_value_len,',  # 调用Fortran函数时传递返回值和长度
        'callfortranroutine':['    #name#_return_value_len = #rlength#;',  # 设置返回值的长度
                              '    if ((#name#_return_value = (string)malloc('  # 分配返回值内存
                              + '#name#_return_value_len+1) == NULL) {',  # 检查内存分配是否成功
                              '        PyErr_SetString(PyExc_MemoryError, \"out of memory\");',  # 内存分配失败时设置异常
                              '        f2py_success = 0;',  # 设置f2py_success为0表示失败
                              '    } else {',  # 如果内存分配成功
                              "        (#name#_return_value)[#name#_return_value_len] = '\\0';",  # 将返回值字符串结束符设为'\0'
                              '    }',
                              '    if (f2py_success) {',  # 如果f2py执行成功
                              {hasexternals: """\
        if (#setjmpbuf#) {  # 如果存在externals并且setjmpbuf为真
            f2py_success = 0;  # 设置f2py_success为0表示失败
        } else {"""},  # 否则开始执行以下操作
                              {isthreadsafe: '        Py_BEGIN_ALLOW_THREADS'},  # 如果是线程安全的,则开始线程
                              """\
#ifdef USESCOMPAQFORTRAN
        (*f2py_func)(#callcompaqfortran#);  # 调用Compaq Fortran代码段
#else
        (*f2py_func)(#callfortran#);  # 调用Fortran代码段
#endif
[
    {  # Code block definition for C/API function argument rules
        'separatorsfor': sepdict
    },
    {  # Common rules for processing auxiliary variables from Python objects
        'frompyobj': [
            '    /* Processing auxiliary variable #varname# */',
            {debugcapi: '    fprintf(stderr,"#vardebuginfo#\\n");'},
        ],
        'cleanupfrompyobj': '    /* End of cleaning variable #varname# */',
        'need': typedef_need_dict,
    },
    {  # Declaration and initialization of non-complex scalar variables
        'decl': '    #ctype# #varname# = 0;',
        'need': {hasinitvalue: 'math.h'},
        'frompyobj': {hasinitvalue: '    #varname# = #init#;'},
        '_check': l_and(isscalar, l_not(iscomplex)),
    },
    {  # Return statement configuration for non-complex scalar variables
        'return': ',#varname#',
        'docstrout': '#pydocsignout#',
        'docreturn': '#outvarname#,',
        'returnformat': '#varrformat#',
        '_check': l_and(isscalar, l_not(iscomplex), isintent_out),
    },
    {  # Declaration of complex scalar variables
        'decl': '    #ctype# #varname#;',
        'frompyobj': {hasinitvalue: '    #varname#.r = #init.r#, #varname#.i = #init.i#;'},
        '_check': iscomplex
    }
]
    # String
    {  # Common
        'decl': ['    #ctype# #varname# = NULL;',  # 声明一个空指针,类型为 #ctype#
                 '    int slen(#varname#);',  # 声明一个函数原型,函数名为 slen,参数为 #varname#,返回类型为 int
                 ],
        'need':['len..'],  # 需要长度信息
        '_check': isstring  # 执行 isstring 函数进行检查
    },
    # Array
    {  # Common
        'decl': ['    #ctype# *#varname# = NULL;',  # 声明一个空指针,类型为 #ctype#
                 '    npy_intp #varname#_Dims[#rank#] = {#rank*[-1]#};',  # 声明一个数组,其维度为 #rank#,每个维度大小为 -1
                 '    const int #varname#_Rank = #rank#;',  # 声明一个常量整数,值为 #rank#
                 ],
        'need':['len..', {hasinitvalue: 'forcomb'}, {hasinitvalue: 'CFUNCSMESS'}],  # 需要长度信息,以及某些初始化值
        '_check': isarray  # 执行 isarray 函数进行检查
    },
    # Scalararray
    {  # Common
        '_check': l_and(isarray, l_not(iscomplexarray))  # 检查是否是标量数组且不是复数数组
    }, {  # Not hidden
        '_check': l_and(isarray, l_not(iscomplexarray), isintent_nothide)  # 检查是否是标量数组、非复数数组且意图不隐藏
    },
    # Integer*1 array
    {'need': '#ctype#',  # 需要类型为 #ctype# 的数据
     '_check': isint1array,  # 执行 isint1array 函数进行检查
     '_depend': ''  # 依赖为空
     },
    # Integer*-1 array
    {'need': '#ctype#',  # 需要类型为 #ctype# 的数据
     '_check': l_or(isunsigned_chararray, isunsigned_char),  # 检查是否是无符号 char 数组或者无符号 char
     '_depend': ''  # 依赖为空
     },
    # Integer*-2 array
    {'need': '#ctype#',  # 需要类型为 #ctype# 的数据
     '_check': isunsigned_shortarray,  # 检查是否是无符号 short 数组
     '_depend': ''  # 依赖为空
     },
    # Integer*-8 array
    {'need': '#ctype#',  # 需要类型为 #ctype# 的数据
     '_check': isunsigned_long_longarray,  # 检查是否是无符号 long long 数组
     '_depend': ''  # 依赖为空
     },
    # Complexarray
    {'need': '#ctype#',  # 需要类型为 #ctype# 的数据
     '_check': iscomplexarray,  # 检查是否是复数数组
     '_depend': ''  # 依赖为空
     },
    # Stringarray
    {
        'callfortranappend': {isarrayofstrings: 'flen(#varname#),'},  # 如果是字符串数组,调用 Fortran 函数追加字符串长度信息
        'need': 'string',  # 需要字符串类型
        '_check': isstringarray  # 检查是否是字符串数组
    }
]

arg_rules = [
    {  # 定义一个字典,用于指定不同规则的参数处理方式
        'separatorsfor': sepdict  # 指定分隔符的字典,用于某些处理
    },
    {  # 常见规则
        'frompyobj': [  # 从 Python 对象转换过来的处理
            '    /* Processing variable #varname# */',  # 处理变量 #varname# 的过程注释
            {debugcapi: '    fprintf(stderr,"#vardebuginfo#\\n");'},  # 如果启用了 debugcapi,输出变量的调试信息到 stderr
        ],
        'cleanupfrompyobj': '    /* End of cleaning variable #varname# */',  # 清理变量 #varname# 结束的注释
        '_depend': '',  # 依赖项为空字符串
        'need': typedef_need_dict,  # 指定需要的类型定义的字典
    },
    # 文档签名
    {
        'docstropt': {l_and(isoptional, isintent_nothide): '#pydocsign#'},  # 可选参数且意图不隐藏时的文档字符串签名
        'docstrreq': {l_and(isrequired, isintent_nothide): '#pydocsign#'},  # 必需参数且意图不隐藏时的文档字符串签名
        'docstrout': {isintent_out: '#pydocsignout#'},  # 输出参数的文档字符串签名
        'latexdocstropt': {  # 可选参数且意图不隐藏时的 LaTeX 文档字符串签名
            l_and(isoptional, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}',  # LaTeX 格式化输出
                                                  {hasnote: '--- #note#'}  # 如果有注释,添加注释信息
                                                  ]
        },
        'latexdocstrreq': {  # 必需参数且意图不隐藏时的 LaTeX 文档字符串签名
            l_and(isrequired, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}',  # LaTeX 格式化输出
                                                  {hasnote: '--- #note#'}  # 如果有注释,添加注释信息
                                                  ]
        },
        'latexdocstrout': {  # 输出参数的 LaTeX 文档字符串签名
            isintent_out: ['\\item[]{{}\\verb@#pydocsignout#@{}}',  # LaTeX 格式化输出
                          {l_and(hasnote, isintent_hide): '--- #note#',  # 如果有注释且意图隐藏,添加注释信息
                           l_and(hasnote, isintent_nothide): '--- See above.'  # 如果有注释且意图不隐藏,指向上述信息
                           }]
        },
        'depend': ''  # 依赖项为空字符串
    },
    # 必需/可选参数
    {
        'kwlist': '"#varname#",',  # 关键字参数列表的格式化输出
        'docsign': '#varname#,',  # 文档签名中的变量名格式化输出
        '_check': l_and(isintent_nothide, l_not(isoptional))  # 检查意图不隐藏且不是可选参数的条件
    },
    {
        'kwlistopt': '"#varname#",',  # 可选关键字参数列表的格式化输出
        'docsignopt': '#varname#=#showinit#,',  # 可选参数的文档签名格式化输出(包括初始值)
        'docsignoptshort': '#varname#,',  # 简短格式的可选参数的文档签名格式化输出
        '_check': l_and(isintent_nothide, isoptional)  # 检查意图不隐藏且是可选参数的条件
    },
    # 文档字符串/BuildValue
    {
        'docreturn': '#outvarname#,',  # 返回值的文档字符串格式化输出
        'returnformat': '#varrformat#',  # 返回格式的变量格式化输出
        '_check': isintent_out  # 检查是否是输出参数的条件
    },
    # 外部调用(回调函数)
    {  # Common
        'docsignxa': {isintent_nothide: '#varname#_extra_args=(),'},
        # 定义 'docsignxa' 键的值为包含 isintent_nothide 的字典,表示额外参数默认为空元组。
        
        'docsignxashort': {isintent_nothide: '#varname#_extra_args,'},
        # 定义 'docsignxashort' 键的值为包含 isintent_nothide 的字典,表示额外参数的简短形式。
        
        'docstropt': {isintent_nothide: '#varname#_extra_args : input tuple, optional\\n    Default: ()'},
        # 定义 'docstropt' 键的值为包含 isintent_nothide 的字典,表示可选输入元组形式的额外参数,默认为空。
        
        'docstrcbs': '#cbdocstr#',
        # 定义 'docstrcbs' 键的值为 '#cbdocstr#',可能用于文档字符串中的回调描述。
        
        'latexdocstrcbs': '\\item[] #cblatexdocstr#',
        # 定义 'latexdocstrcbs' 键的值为 LaTeX 风格的表项,使用 #cblatexdocstr# 描述。
        
        'latexdocstropt': {isintent_nothide: '\\item[]{{}\\verb@#varname#_extra_args := () input tuple@{}} --- Extra arguments for call-back function {{}\\verb@#varname#@{}}.'},
        # 定义 'latexdocstropt' 键的值为包含 isintent_nothide 的字典,为回调函数描述提供 LaTeX 格式的额外参数说明。
        
        'decl': ['    #cbname#_t #varname#_cb = { Py_None, NULL, 0 };',
                 '    #cbname#_t *#varname#_cb_ptr = &#varname#_cb;',
                 '    PyTupleObject *#varname#_xa_capi = NULL;',
                 {l_not(isintent_callback):
                  '    #cbname#_typedef #varname#_cptr;'}
                 ],
        # 定义 'decl' 键的值为包含多个声明字符串的列表,其中包括回调函数的默认初始化、指针和可能的类型定义。
        
        'kwlistxa': {isintent_nothide: '"#varname#_extra_args",'},
        # 定义 'kwlistxa' 键的值为包含 isintent_nothide 的字典,表示关键字参数列表中包含额外参数的名称。
        
        'argformat': {isrequired: 'O'},
        # 定义 'argformat' 键的值为包含 isrequired 的字典,指示参数的格式要求为一个对象。
        
        'keyformat': {isoptional: 'O'},
        # 定义 'keyformat' 键的值为包含 isoptional 的字典,指示关键字的格式要求为一个对象。
        
        'xaformat': {isintent_nothide: 'O!'},
        # 定义 'xaformat' 键的值为包含 isintent_nothide 的字典,指示额外参数的格式要求为对象且必须存在。
        
        'args_capi': {isrequired: ',&#varname#_cb.capi'},
        # 定义 'args_capi' 键的值为包含 isrequired 的字典,表示参数列表中包含 C API 的参数。
        
        'keys_capi': {isoptional: ',&#varname#_cb.capi'},
        # 定义 'keys_capi' 键的值为包含 isoptional 的字典,表示关键字参数中包含 C API 的参数。
        
        'keys_xa': ',&PyTuple_Type,&#varname#_xa_capi',
        # 定义 'keys_xa' 键的值为字符串,包含元组类型的 Pyhton 类型和对应的 C API 参数。
        
        'setjmpbuf': '(setjmp(#varname#_cb.jmpbuf))',
        # 定义 'setjmpbuf' 键的值为 setjmp 函数对给定的跳转缓冲区(jmpbuf)进行调用。
        
        'callfortran': {l_not(isintent_callback): '#varname#_cptr,'},
        # 定义 'callfortran' 键的值为包含 l_not(isintent_callback) 的字典,表示用于调用 Fortran 的函数指针。
        
        'need': ['#cbname#', 'setjmp.h'],
        # 定义 'need' 键的值为列表,包含所需的回调函数和头文件 'setjmp.h'。
        
        '_check': isexternal
        # 定义 '_check' 键的值为 isexternal,可能用于指示外部检查的标志。
    },
    {  # Specific block
        'frompyobj': [{l_not(isintent_callback): """\
# 检查是否符合 F2PyCapsule 的检查条件
if(F2PyCapsule_Check(#varname#_cb.capi)) {
  #varname#_cptr = F2PyCapsule_AsVoidPtr(#varname#_cb.capi);
} else {
  #varname#_cptr = #cbname#;
}



# 如果回调函数的 C API 是 Py_None,则尝试从指定模块中获取回调函数 #varname#
if (#varname#_cb.capi==Py_None) {
  #varname#_cb.capi = PyObject_GetAttrString(#modulename#_module,\"#varname#\");
  if (#varname#_cb.capi) {
    # 检查是否需要额外的参数
    if (#varname#_xa_capi==NULL) {
      # 如果模块中存在 #varname#_extra_args 属性,则将其转换为元组
      if (PyObject_HasAttrString(#modulename#_module,\"#varname#_extra_args\")) {
        PyObject* capi_tmp = PyObject_GetAttrString(#modulename#_module,\"#varname#_extra_args\");
        if (capi_tmp) {
          #varname#_xa_capi = (PyTupleObject *)PySequence_Tuple(capi_tmp);
          Py_DECREF(capi_tmp);
        }
        else {
          # 如果未能成功获取 #varname#_extra_args 属性,则创建一个空元组
          #varname#_xa_capi = (PyTupleObject *)Py_BuildValue(\"()\");
        }
        # 检查是否成功转换为元组
        if (#varname#_xa_capi==NULL) {
          PyErr_SetString(#modulename#_error,\"Failed to convert #modulename#.#varname#_extra_args to tuple.\\n\");
          return NULL;
        }
      }
    }
  }
  # 如果未能成功获取回调函数 #varname#,则报错
  if (#varname#_cb.capi==NULL) {
    PyErr_SetString(#modulename#_error,\"Callback #varname# not defined (as an argument or module #modulename# attribute).\\n\");
    return NULL;
  }
}



# 创建回调函数的参数列表,如果失败则报错
if (create_cb_arglist(#varname#_cb.capi,#varname#_xa_capi,#maxnofargs#,#nofoptargs#,&#varname#_cb.nofargs,&#varname#_cb.args_capi,\"failed in processing argument list for call-back #varname#.\")) {



# 输出调试信息,显示回调函数的预期参数数量
fprintf(stderr,\"debug-capi:Assuming %d arguments; at most #maxnofargs#(-#nofoptargs#) is expected.\\n\",#varname#_cb.nofargs);
# 打印调试信息,显示回调函数的当前值
CFUNCSMESSPY(\"for #varname#=\",#varname#_cb.capi);



# 打印消息,表示正在保存回调函数的变量
CFUNCSMESS(\"Saving callback variables for `#varname#`.\\n\");
# 交换活跃的回调函数指针
#varname#_cb_ptr = swap_active_#cbname#(#varname#_cb_ptr);



# 打印消息,表示正在恢复回调函数的变量
CFUNCSMESS(\"Restoring callback variables for `#varname#`.\\n\");
# 交换活跃的回调函数指针
#varname#_cb_ptr = swap_active_#cbname#(#varname#_cb_ptr);
# 释放回调函数参数列表的 Python 对象引用
Py_DECREF(#varname#_cb.args_capi);
    }, {  # Not hidden
        'decl': '    PyObject *#varname#_capi = Py_None;',
        # 声明一个名为 #varname#_capi 的 PyObject 指针变量,初始化为 Py_None
        'argformat': {isrequired: 'O'},
        # 指定参数格式,isrequired 对应 'O' 表示必须的参数类型为 PyObject
        'keyformat': {isoptional: 'O'},
        # 指定关键字参数格式,isoptional 对应 'O' 表示可选的参数类型为 PyObject
        'args_capi': {isrequired: ',&#varname#_capi'},
        # 定义参数列表中的 #varname#_capi,作为必需参数
        'keys_capi': {isoptional: ',&#varname#_capi'},
        # 定义关键字参数中的 #varname#_capi,作为可选参数
        'pyobjfrom': {isintent_inout: """\
    f2py_success = try_pyarr_from_#ctype#(#varname#_capi,&#varname#);
    if (f2py_success) {"""},
        # 根据 isintent_inout 条件,执行从 PyObject 到 #ctype# 的转换,检查转换成功后的处理逻辑
        'closepyobjfrom': {isintent_inout: "    } /*if (f2py_success) of #varname# pyobjfrom*/"},
        # 根据 isintent_inout 条件,关闭 PyObject 到 #ctype# 的转换逻辑
        'need': {isintent_inout: 'try_pyarr_from_#ctype#'},
        # 指定需要进行 PyObject 到 #ctype# 转换的条件
        '_check': l_and(isscalar, l_not(iscomplex), l_not(isstring),
                        isintent_nothide)
        # 检查条件,确保是标量、非复数、非字符串,并且不隐藏意图
    }, {
        'frompyobj': [
            # 根据条件不同,执行不同的赋值逻辑,从 PyObject 到变量 #varname# 的转换
            {hasinitvalue: '    if (#varname#_capi == Py_None) #varname# = #init#; else',
             '_depend': ''},
            {l_and(isoptional, l_not(hasinitvalue)): '    if (#varname#_capi != Py_None)',
             '_depend': ''},
            {l_not(islogical): '''\
        f2py_success = #ctype#_from_pyobj(&#varname#,#varname#_capi,"#pyname#() #nth# (#varname#) can\'t be converted to #ctype#");
    if (f2py_success) {'''},
            {islogical: '''\
        #varname# = (#ctype#)PyObject_IsTrue(#varname#_capi);
        f2py_success = 1;
    if (f2py_success) {'''},
        ],
        # 根据不同的条件,执行从 PyObject 到 #ctype# 的转换逻辑,检查转换成功后的处理逻辑
        'cleanupfrompyobj': '    } /*if (f2py_success) of #varname#*/',
        # 执行从 PyObject 到 #ctype# 的转换后,进行清理逻辑
        'need': {l_not(islogical): '#ctype#_from_pyobj'},
        # 指定需要进行 PyObject 到 #ctype# 转换的条件
        '_check': l_and(isscalar, l_not(iscomplex), isintent_nothide),
        # 检查条件,确保是标量、非复数,并且不隐藏意图
        '_depend': ''
    }, {  # Hidden
        'frompyobj': {hasinitvalue: '    #varname# = #init#;'},
        # 根据 hasinitvalue 条件,执行隐藏意图的赋值逻辑,从 PyObject 到变量 #varname# 的转换
        'need': typedef_need_dict,
        # 指定需要的 typedef 字典
        '_check': l_and(isscalar, l_not(iscomplex), isintent_hide),
        # 检查条件,确保是标量、非复数,并且隐藏意图
        '_depend': ''
    }, {  # Common
        'frompyobj': {debugcapi: '    fprintf(stderr,"#vardebugshowvalue#\\n",#varname#);'},
        # 根据 debugcapi 条件,执行常见的从 PyObject 到 #varname# 的转换逻辑
        '_check': l_and(isscalar, l_not(iscomplex)),
        # 检查条件,确保是标量、非复数
        '_depend': ''
    },
    # Complex scalars
    {  # Common
        'decl': '    #ctype# #varname#;',
        # 声明复杂标量类型的 #varname# 变量
        'callfortran': {isintent_c: '#varname#,', l_not(isintent_c): '&#varname#,'},
        # 根据 isintent_c 条件,生成调用 Fortran 代码的字符串
        'pyobjfrom': {debugcapi: '    fprintf(stderr,"#vardebugshowvalue#\\n",#varname#.r,#varname#.i);'},
        # 根据 debugcapi 条件,执行复杂标量类型的从 PyObject 到 #varname# 的转换逻辑
        'return': {isintent_out: ',#varname#_capi'},
        # 根据 isintent_out 条件,指定返回 #varname#_capi 的值
        '_check': iscomplex
        # 检查条件,确保是复杂标量
    }, {  # Not hidden
        'decl': '    PyObject *#varname#_capi = Py_None;',  # 声明一个名为 #varname#_capi 的 PyObject 指针变量,初始化为 Py_None
        'argformat': {isrequired: 'O'},  # 参数格式化信息,要求为必需参数,格式为 'O'
        'keyformat': {isoptional: 'O'},  # 关键字格式化信息,要求为可选参数,格式为 'O'
        'args_capi': {isrequired: ',&#varname#_capi'},  # 参数的 C API 格式化信息,要求为必需参数
        'keys_capi': {isoptional: ',&#varname#_capi'},  # 关键字的 C API 格式化信息,要求为可选参数
        'need': {isintent_inout: 'try_pyarr_from_#ctype#'},  # 需要的信息,表明是输入输出参数,需要调用 try_pyarr_from_#ctype#
        'pyobjfrom': {isintent_inout: """\  # 从 Python 对象转换而来的信息,表明是输入输出参数
        f2py_success = try_pyarr_from_#ctype#(#varname#_capi,&#varname#);
        if (f2py_success) {"""},
        'closepyobjfrom': {isintent_inout: "        } /*if (f2py_success) of #varname# pyobjfrom*/"},  # 关闭从 Python 对象转换的操作
        '_check': l_and(iscomplex, isintent_nothide)  # 检查条件,复杂类型且非隐藏意图
    }, {
        'frompyobj': [{hasinitvalue: '    if (#varname#_capi==Py_None) {#varname#.r = #init.r#, #varname#.i = #init.i#;} else'},  # 从 Python 对象转换而来的操作,具有初始值的情况下处理
                      {l_and(isoptional, l_not(hasinitvalue)): '    if (#varname#_capi != Py_None)'},  # 可选参数且无初始值的情况下处理
                      '        f2py_success = #ctype#_from_pyobj(&#varname#,#varname#_capi,"#pyname#() #nth# (#varname#) can\'t be converted to #ctype#");'
                      '\n    if (f2py_success) {'],  # 调用函数尝试从 Python 对象转换为给定类型,如果成功则继续执行
        'cleanupfrompyobj': '    }  /*if (f2py_success) of #varname# frompyobj*/',  # 清理从 Python 对象转换操作的代码块
        'need': ['#ctype#_from_pyobj'],  # 需要的信息,调用了 #ctype#_from_pyobj 函数
        '_check': l_and(iscomplex, isintent_nothide),  # 检查条件,复杂类型且非隐藏意图
        '_depend': ''  # 依赖信息为空
    }, {  # Hidden
        'decl': {isintent_out: '    PyObject *#varname#_capi = Py_None;'},  # 隐藏的声明,输出意图的 PyObject 指针变量,初始化为 Py_None
        '_check': l_and(iscomplex, isintent_hide)  # 检查条件,复杂类型且隐藏意图
    }, {
        'frompyobj': {hasinitvalue: '    #varname#.r = #init.r#, #varname#.i = #init.i#;'},  # 从 Python 对象转换而来的操作,具有初始值的情况下处理
        '_check': l_and(iscomplex, isintent_hide),  # 检查条件,复杂类型且隐藏意图
        '_depend': ''  # 依赖信息为空
    }, {  # Common
        'pyobjfrom': {isintent_out: '    #varname#_capi = pyobj_from_#ctype#1(#varname#);'},  # 通用的从 Python 对象转换操作,输出意图
        'need': ['pyobj_from_#ctype#1'],  # 需要的信息,调用了 pyobj_from_#ctype#1 函数
        '_check': iscomplex  # 检查条件,复杂类型
    }, {
        'frompyobj': {debugcapi: '    fprintf(stderr,"#vardebugshowvalue#\\n",#varname#.r,#varname#.i);'},  # 从 Python 对象转换而来的操作,输出调试信息
        '_check': iscomplex,  # 检查条件,复杂类型
        '_depend': ''  # 依赖信息为空
    },
    # String
    {  # Common
        'decl': ['    #ctype# #varname# = NULL;',  # 声明一个指向 #ctype# 类型的变量 #varname#,初始化为 NULL
                 '    int slen(#varname#);',  # 声明一个名为 slen 的整数变量,初始化为调用函数 slen(#varname#)
                 '    PyObject *#varname#_capi = Py_None;'],  # 声明一个名为 #varname#_capi 的 PyObject 指针变量,初始化为 Py_None
        'callfortran':'#varname#,',  # 调用 Fortran 函数时的参数信息
        'callfortranappend':'slen(#varname#),',  # 调用 Fortran 函数时追加的参数信息,调用函数 slen(#varname#)
        'pyobjfrom':[
            {debugcapi:
             '    fprintf(stderr,'
             '"#vardebugshowvalue#\\n",slen(#varname#),#varname#);'},  # 从 Python 对象转换而来的操作,输出调试信息
            {l_and(isintent_out, l_not(isintent_c)):
             "        STRINGPADN(#varname#, slen(#varname#), ' ', '\\0');"},  # 从 Python 对象转换而来的操作,处理输出意图且非 C 类型的情况
        ],
        'return': {isintent_out: ',#varname#'},  # 返回值的信息,输出意图
        'need': ['len..',  # 需要的信息,包含字符串长度操作
                 {l_and(isintent_out, l_not(isintent_c)): 'STRINGPADN'}],  # 需要的信息,处理输出意图且非 C 类型的情况
        '_check': isstring  # 检查条件,字符串类型
    }, {  # Common
        'frompyobj': [
            """\
    slen(#varname#) = #elsize#;
    f2py_success = #ctype#_from_pyobj(&#varname#,&slen(#varname#),#init#,"""  # 从 Python 对象转换而来的操作,设置字符串长度并调用函数尝试转换为给定类型
"""#varname#_capi,\"#ctype#_from_pyobj failed in converting #nth#"""
"""`#varname#\' of #pyname# to C #ctype#\");
    if (f2py_success) {""",
            # The trailing null value for Fortran is blank.
            {l_not(isintent_c):
             "        STRINGPADN(#varname#, slen(#varname#), '\\0', ' ');"},
        ],
        'cleanupfrompyobj': """\
        STRINGFREE(#varname#);
    }  /*if (f2py_success) of #varname#*/""",
        'need': ['#ctype#_from_pyobj', 'len..', 'STRINGFREE',
                 {l_not(isintent_c): 'STRINGPADN'}],
        '_check':isstring,
        '_depend':''
    }, {  # Not hidden
        'argformat': {isrequired: 'O'},
        'keyformat': {isoptional: 'O'},
        'args_capi': {isrequired: ',&#varname#_capi'},
        'keys_capi': {isoptional: ',&#varname#_capi'},
        'pyobjfrom': [
            {l_and(isintent_inout, l_not(isintent_c)):
             "        STRINGPADN(#varname#, slen(#varname#), ' ', '\\0');"},
            {isintent_inout: '''\
    f2py_success = try_pyarr_from_#ctype#(#varname#_capi, #varname#,
                                          slen(#varname#));
    if (f2py_success) {'''}],
        'closepyobjfrom': {isintent_inout: '    } /*if (f2py_success) of #varname# pyobjfrom*/'},
        'need': {isintent_inout: 'try_pyarr_from_#ctype#',
                 l_and(isintent_inout, l_not(isintent_c)): 'STRINGPADN'},
        '_check': l_and(isstring, isintent_nothide)
    }, {  # Hidden
        '_check': l_and(isstring, isintent_hide)
    }, {
        'frompyobj': {debugcapi: '    fprintf(stderr,"#vardebugshowvalue#\\n",slen(#varname#),#varname#);'},
        '_check': isstring,
        '_depend': ''
    },
    # Array
    {  # Common
        'decl': ['    #ctype# *#varname# = NULL;',
                 '    npy_intp #varname#_Dims[#rank#] = {#rank*[-1]#};',
                 '    const int #varname#_Rank = #rank#;',
                 '    PyArrayObject *capi_#varname#_as_array = NULL;',
                 '    int capi_#varname#_intent = 0;',
                 {isstringarray: '    int slen(#varname#) = 0;'},
                 ],
        'callfortran':'#varname#,',
        'callfortranappend': {isstringarray: 'slen(#varname#),'},
        'return': {isintent_out: ',capi_#varname#_as_array'},
        'need': 'len..',
        '_check': isarray
    }, {  # intent(overwrite) array
        'decl': '    int capi_overwrite_#varname# = 1;',
        'kwlistxa': '"overwrite_#varname#",',
        'xaformat': 'i',
        'keys_xa': ',&capi_overwrite_#varname#',
        'docsignxa': 'overwrite_#varname#=1,',
        'docsignxashort': 'overwrite_#varname#,',
        'docstropt': 'overwrite_#varname# : input int, optional\\n    Default: 1',
        '_check': l_and(isarray, isintent_overwrite),
    }, {
        'frompyobj': '    capi_#varname#_intent |= (capi_overwrite_#varname#?0:F2PY_INTENT_COPY);',
        '_check': l_and(isarray, isintent_overwrite),
        '_depend': '',
    },
    {  # intent(copy) array
        'decl': '    int capi_overwrite_#varname# = 0;',
        'kwlistxa': '"overwrite_#varname#",',
        'xaformat': 'i',
        'keys_xa': ',&capi_overwrite_#varname#',
        'docsignxa': 'overwrite_#varname#=0,',
        'docsignxashort': 'overwrite_#varname#,',
        'docstropt': 'overwrite_#varname# : input int, optional\\n    Default: 0',
        '_check': l_and(isarray, isintent_copy),
    }, {
        'frompyobj': '    capi_#varname#_intent |= (capi_overwrite_#varname#?0:F2PY_INTENT_COPY);',
        '_check': l_and(isarray, isintent_copy),
        '_depend': '',
    }, {
        'need': [{hasinitvalue: 'forcomb'}, {hasinitvalue: 'CFUNCSMESS'}],
        '_check': isarray,
        '_depend': ''
    }, {  # Not hidden
        'decl': '    PyObject *#varname#_capi = Py_None;',
        'argformat': {isrequired: 'O'},
        'keyformat': {isoptional: 'O'},
        'args_capi': {isrequired: ',&#varname#_capi'},
        'keys_capi': {isoptional: ',&#varname#_capi'},
        '_check': l_and(isarray, isintent_nothide)
    }, {
        'frompyobj': [
            '    #setdims#;',
            '    capi_#varname#_intent |= #intent#;',
            ('    const char * capi_errmess = "#modulename#.#pyname#:'
             ' failed to create array from the #nth# `#varname#`";'),
            {isintent_hide:
             '    capi_#varname#_as_array = ndarray_from_pyobj('
             '  #atype#,#elsize#,#varname#_Dims,#varname#_Rank,'
             '  capi_#varname#_intent,Py_None,capi_errmess);'},
            {isintent_nothide:
             '    capi_#varname#_as_array = ndarray_from_pyobj('
             '  #atype#,#elsize#,#varname#_Dims,#varname#_Rank,'
             '  capi_#varname#_intent,#varname#_capi,capi_errmess);'},
            """\
    if (capi_#varname#_as_array == NULL) {
        PyObject* capi_err = PyErr_Occurred();
        if (capi_err == NULL) {
            capi_err = #modulename#_error;
            PyErr_SetString(capi_err, capi_errmess);
        }
    } else {
        #varname# = (#ctype# *)(PyArray_DATA(capi_#varname#_as_array));
        # code block intent set
# 定义了一个名为`cleanupfrompyobj`的字典列表,用于存储特定清理操作的规则
'cleanupfrompyobj': [
    '    }  '  # 关闭块注释
    '/* if (capi_#varname#_as_array == NULL) ... else of #varname# */',  # 处理特定条件下的注释
    {l_not(l_or(isintent_out, isintent_hide)): """\
    if((PyObject *)capi_#varname#_as_array!=#varname#_capi) {
        Py_XDECREF(capi_#varname#_as_array); }"""},  # 根据条件释放特定对象
    {l_and(isintent_hide, l_not(isintent_out)): """\
        Py_XDECREF(capi_#varname#_as_array);"""},  # 处理隐藏变量的清理操作
    {hasinitvalue: '    }  /*if (f2py_success) of #varname# init*/'},  # 处理初始化成功的情况
],

# 规则用于检查数组的相关定义
'check_rules': [
    {
        'frompyobj': {debugcapi: '    fprintf(stderr,\"debug-capi:Checking `#check#\'\\n\");'},  # 输出用于调试的语句
        'need': 'len..'  # 指定检查的需求条件
    }
]
    }, {
        # 开始定义一个新的字典条目,包含从 Python 对象到 C 代码的转换
        'frompyobj': '    CHECKSCALAR(#check#,\"#check#\",\"#nth# #varname#\",\"#varshowvalue#\",#varname#) {',
        # 在 C 代码中生成用于检查标量的宏定义
        'cleanupfrompyobj': '    } /*CHECKSCALAR(#check#)*/',
        # 需要定义一个标量检查
        'need': 'CHECKSCALAR',
        # 执行标量检查的条件:既不是复数,也不是复杂对象
        '_check': l_and(isscalar, l_not(iscomplex)),
        # 在此处没有需要中断的附加操作
        '_break': ''
    }, {
        # 开始定义一个新的字典条目,包含从 Python 对象到 C 代码的转换
        'frompyobj': '    CHECKSTRING(#check#,\"#check#\",\"#nth# #varname#\",\"#varshowvalue#\",#varname#) {',
        # 在 C 代码中生成用于检查字符串的宏定义
        'cleanupfrompyobj': '    } /*CHECKSTRING(#check#)*/',
        # 需要定义一个字符串检查
        'need': 'CHECKSTRING',
        # 执行字符串检查的条件:对象是字符串
        '_check': isstring,
        # 在此处没有需要中断的附加操作
        '_break': ''
    }, {
        # 需要定义一个数组检查
        'need': 'CHECKARRAY',
        # 在 C 代码中生成用于检查数组的宏定义
        'frompyobj': '    CHECKARRAY(#check#,\"#check#\",\"#nth# #varname#\") {',
        # 在 C 代码中生成用于清理数组检查的宏定义
        'cleanupfrompyobj': '    } /*CHECKARRAY(#check#)*/',
        # 执行数组检查的条件:对象是数组
        '_check': isarray,
        # 在此处没有需要中断的附加操作
        '_break': ''
    }, {
        # 需要定义一个通用检查
        'need': 'CHECKGENERIC',
        # 在 C 代码中生成用于通用检查的宏定义
        'frompyobj': '    CHECKGENERIC(#check#,\"#check#\",\"#nth# #varname#\") {',
        # 在 C 代码中生成用于清理通用检查的宏定义
        'cleanupfrompyobj': '    } /*CHECKGENERIC(#check#)*/',
        # 在此处没有需要中断的附加操作
    }
# 构建模块的函数,接收两个参数:m 表示模块信息,um 表示未使用的参数
def buildmodule(m, um):
    """
    构建模块函数,处理模块相关的构建工作并返回结果字典。

    参数:
    m -- 包含模块信息的字典
    um -- 未使用的参数,此处未被使用

    返回:
    ret -- 返回一个空字典作为占位符

    """

    # 输出构建模块的信息
    outmess('    Building module "%s"...\n' % (m['name']))

    # 初始化返回的字典
    ret = {}

    # 复制模块规则列表到 mod_rules
    mod_rules = defmod_rules[:]

    # 将模块签名映射为字典 vrd
    vrd = capi_maps.modsign2map(m)

    # 构建包含 f2py 版本信息的字典 rd
    rd = dictappend({'f2py_version': f2py_version}, vrd)

    # 初始化函数包装器列表
    funcwrappers = []

    # 初始化 F90 代码的函数包装器列表
    funcwrappers2 = []  # F90 codes

    # 遍历模块的 interfaced 列表
    for n in m['interfaced']:
        nb = None

        # 在模块的 body 中查找对应的接口块
        for bi in m['body']:
            if bi['block'] not in ['interface', 'abstract interface']:
                errmess('buildmodule: Expected interface block. Skipping.\n')
                continue
            for b in bi['body']:
                if b['name'] == n:
                    nb = b
                    break

        # 如果未找到接口块,输出错误信息并跳过
        if not nb:
            print(
                'buildmodule: Could not find the body of interfaced routine "%s". Skipping.\n' % (n), file=sys.stderr)
            continue

        # 创建接口块列表,包含当前接口块及其 entry 属性的深拷贝
        nb_list = [nb]
        if 'entry' in nb:
            for k, a in nb['entry'].items():
                nb1 = copy.deepcopy(nb)
                del nb1['entry']
                nb1['name'] = k
                nb1['args'] = a
                nb_list.append(nb1)

        # 遍历接口块列表
        for nb in nb_list:
            # 检查是否需要 F90 包装器
            isf90 = requiresf90wrapper(nb)

            # 如果选项中包含 emptygen,生成可能为空的包装器文件
            if options['emptygen']:
                b_path = options['buildpath']
                m_name = vrd['modulename']
                outmess('    Generating possibly empty wrappers"\n')
                Path(f"{b_path}/{vrd['coutput']}").touch()
                if isf90:
                    outmess(f'    Maybe empty "{m_name}-f2pywrappers2.f90"\n')
                    Path(f'{b_path}/{m_name}-f2pywrappers2.f90').touch()
                    outmess(f'    Maybe empty "{m_name}-f2pywrappers.f"\n')
                    Path(f'{b_path}/{m_name}-f2pywrappers.f').touch()
                else:
                    outmess(f'    Maybe empty "{m_name}-f2pywrappers.f"\n')
                    Path(f'{b_path}/{m_name}-f2pywrappers.f').touch()

            # 构建 API 和包装器
            api, wrap = buildapi(nb)

            # 如果存在包装器,根据是否为 F90 添加到对应列表
            if wrap:
                if isf90:
                    funcwrappers2.append(wrap)
                else:
                    funcwrappers.append(wrap)

            # 应用规则并更新 rd 字典
            ar = applyrules(api, vrd)
            rd = dictappend(rd, ar)

    # 构建 COMMON 块支持
    cr, wrap = common_rules.buildhooks(m)
    if wrap:
        funcwrappers.append(wrap)
    ar = applyrules(cr, vrd)
    rd = dictappend(rd, ar)

    # 构建 F90 模块支持
    mr, wrap = f90mod_rules.buildhooks(m)
    if wrap:
        funcwrappers2.append(wrap)
    ar = applyrules(mr, vrd)
    rd = dictappend(rd, ar)
    # 遍历 um 列表中的元素 u
    for u in um:
        # 使用 use_rules.buildusevars 函数处理 u 和 m['use'][u['name']],返回结果存储在 ar 中
        ar = use_rules.buildusevars(u, m['use'][u['name']])
        # 将 ar 合并到 rd 中
        rd = dictappend(rd, ar)

    # 获取需要的信息集合
    needs = cfuncs.get_needs()
    
    # 向 needs['typedefs'] 中添加从 capi_maps.f2cmap_mapped 中选择的 cvar 元素,条件是 cvar 存在于 typedef_need_dict 的值中
    needs['typedefs'] += [cvar for cvar in capi_maps.f2cmap_mapped
                          if cvar in typedef_need_dict.values()]
    
    # 初始化 code 字典
    code = {}
    
    # 遍历 needs 字典的键
    for n in needs.keys():
        # 将每个键对应的值初始化为空列表
        code[n] = []
        # 遍历 needs[n] 中的每个元素 k
        for k in needs[n]:
            c = ''
            # 根据 k 的值从不同的函数字典中获取对应的字符串 c
            if k in cfuncs.includes0:
                c = cfuncs.includes0[k]
            elif k in cfuncs.includes:
                c = cfuncs.includes[k]
            elif k in cfuncs.userincludes:
                c = cfuncs.userincludes[k]
            elif k in cfuncs.typedefs:
                c = cfuncs.typedefs[k]
            elif k in cfuncs.typedefs_generated:
                c = cfuncs.typedefs_generated[k]
            elif k in cfuncs.cppmacros:
                c = cfuncs.cppmacros[k]
            elif k in cfuncs.cfuncs:
                c = cfuncs.cfuncs[k]
            elif k in cfuncs.callbacks:
                c = cfuncs.callbacks[k]
            elif k in cfuncs.f90modhooks:
                c = cfuncs.f90modhooks[k]
            elif k in cfuncs.commonhooks:
                c = cfuncs.commonhooks[k]
            else:
                # 如果 k 不存在于任何函数字典中,输出错误信息
                errmess('buildmodule: unknown need %s.\n' % (repr(k)))
                continue
            # 将获取的字符串 c 添加到 code[n] 中
            code[n].append(c)
    
    # 将 code 添加到 mod_rules 列表中
    mod_rules.append(code)
    
    # 遍历 mod_rules 列表中的元素 r
    for r in mod_rules:
        # 检查 r 是否包含键 '_check',并且调用 r['_check'](m) 如果条件为真,或者 r 中不包含 '_check'
        if ('_check' in r and r['_check'](m)) or ('_check' not in r):
            # 应用规则 r 到 vrd 和 m 上,结果存储在 ar 中
            ar = applyrules(r, vrd, m)
            # 将 ar 合并到 rd 中
            rd = dictappend(rd, ar)
    
    # 应用 module_rules 到 rd 上,结果存储在 ar 中
    ar = applyrules(module_rules, rd)

    # 构造输出文件的路径 fn
    fn = os.path.join(options['buildpath'], vrd['coutput'])
    # 将 ar['modulebody'] 中的内容写入文件 fn 中,替换其中的制表符为两个空格
    ret['csrc'] = fn
    with open(fn, 'w') as f:
        f.write(ar['modulebody'].replace('\t', 2 * ' '))
    # 输出信息,指示成功写入 C/API 模块到文件中
    outmess('    Wrote C/API module "%s" to file "%s"\n' % (m['name'], fn))

    # 如果 options['dorestdoc'] 为真
    if options['dorestdoc']:
        # 构造 ReST 文档文件的路径 fn
        fn = os.path.join(options['buildpath'], vrd['modulename'] + 'module.rest')
        # 将 ar['restdoc'] 中的内容写入文件 fn 中
        with open(fn, 'w') as f:
            f.write('.. -*- rest -*-\n')
            f.write('\n'.join(ar['restdoc']))
        # 输出信息,指示成功保存 ReST 文档文件
        outmess('    ReST Documentation is saved to file "%s/%smodule.rest"\n' %
                (options['buildpath'], vrd['modulename']))

    # 如果 options['dolatexdoc'] 为真
    if options['dolatexdoc']:
        # 构造 LaTeX 文档文件的路径 fn
        fn = os.path.join(options['buildpath'], vrd['modulename'] + 'module.tex')
        # 将 ar['latexdoc'] 中的内容写入文件 fn 中
        ret['ltx'] = fn
        with open(fn, 'w') as f:
            f.write(
                '%% This file is auto-generated with f2py (version:%s)\n' % (f2py_version))
            if 'shortlatex' not in options:
                f.write(
                    '\\documentclass{article}\n\\usepackage{a4wide}\n\\begin{document}\n\\tableofcontents\n\n')
                f.write('\n'.join(ar['latexdoc']))
            if 'shortlatex' not in options:
                f.write('\\end{document}')
        # 输出信息,指示成功保存 LaTeX 文档文件
        outmess('    Documentation is saved to file "%s/%smodule.tex"\n' %
                (options['buildpath'], vrd['modulename']))
    # 如果存在函数包装器
    if funcwrappers:
        # 拼接生成包装器文件的路径名
        wn = os.path.join(options['buildpath'], vrd['f2py_wrapper_output'])
        # 将文件路径添加到返回结果中的 'fsrc' 键
        ret['fsrc'] = wn
        # 打开文件以写入模式
        with open(wn, 'w') as f:
            # 写入文件头部信息
            f.write('C     -*- fortran -*-\n')
            f.write(
                'C     This file is autogenerated with f2py (version:%s)\n' % (f2py_version))
            f.write(
                'C     It contains Fortran 77 wrappers to fortran functions.\n')
            # 初始化空列表 lines
            lines = []
            # 遍历函数包装器并生成文件内容
            for l in ('\n\n'.join(funcwrappers) + '\n').split('\n'):
                # 如果行中存在注释符号且位于前 66 个字符内,则不分割注释行
                if 0 <= l.find('!') < 66:
                    # 将该行添加到 lines 列表中,并加上换行符
                    lines.append(l + '\n')
                # 如果行不为空且以空格开头
                elif l and l[0] == ' ':
                    # 当行长度大于等于 66 时,分割为多行,并添加到 lines 中
                    while len(l) >= 66:
                        lines.append(l[:66] + '\n     &')
                        l = l[66:]
                    lines.append(l + '\n')
                else:
                    lines.append(l + '\n')
            # 将 lines 列表中的内容连接成字符串,并将多余的换行和连接符去除
            lines = ''.join(lines).replace('\n     &\n', '\n')
            # 将处理好的文件内容写入文件中
            f.write(lines)
        # 输出消息,显示 Fortran 77 包装器文件已保存
        outmess('    Fortran 77 wrappers are saved to "%s"\n' % (wn))
    
    # 如果存在第二组函数包装器
    if funcwrappers2:
        # 拼接生成包装器文件的路径名
        wn = os.path.join(
            options['buildpath'], '%s-f2pywrappers2.f90' % (vrd['modulename']))
        # 将文件路径添加到返回结果中的 'fsrc' 键
        ret['fsrc'] = wn
        # 打开文件以写入模式
        with open(wn, 'w') as f:
            # 写入文件头部信息
            f.write('!     -*- f90 -*-\n')
            f.write(
                '!     This file is autogenerated with f2py (version:%s)\n' % (f2py_version))
            f.write(
                '!     It contains Fortran 90 wrappers to fortran functions.\n')
            # 初始化空列表 lines
            lines = []
            # 遍历第二组函数包装器并生成文件内容
            for l in ('\n\n'.join(funcwrappers2) + '\n').split('\n'):
                # 如果行中存在注释符号且位于前 72 个字符内,则不分割注释行
                if 0 <= l.find('!') < 72:
                    # 将该行添加到 lines 列表中,并加上换行符
                    lines.append(l + '\n')
                # 如果行长度超过 72 并且以空格开头
                elif len(l) > 72 and l[0] == ' ':
                    # 分割为多行,并添加到 lines 中
                    lines.append(l[:72] + '&\n     &')
                    l = l[72:]
                    while len(l) > 66:
                        lines.append(l[:66] + '&\n     &')
                        l = l[66:]
                    lines.append(l + '\n')
                else:
                    lines.append(l + '\n')
            # 将 lines 列表中的内容连接成字符串,并将多余的换行和连接符去除
            lines = ''.join(lines).replace('\n     &\n', '\n')
            # 将处理好的文件内容写入文件中
            f.write(lines)
        # 输出消息,显示 Fortran 90 包装器文件已保存
        outmess('    Fortran 90 wrappers are saved to "%s"\n' % (wn))
    
    # 返回包含生成文件路径的字典 ret
    return ret
# 构建 C/API 函数的过程

# 定义一个字典,将数字转换为对应的英文序数词尾
stnd = {1: 'st', 2: 'nd', 3: 'rd', 4: 'th', 5: 'th',
        6: 'th', 7: 'th', 8: 'th', 9: 'th', 0: 'th'}

# 定义构建 API 函数的主函数
def buildapi(rout):
    # 将函数转换为子程序,同时获取包装信息
    rout, wrap = func2subr.assubr(rout)
    # 获取函数的参数列表和依赖参数
    args, depargs = getargs2(rout)
    # 设置全局变量 capi_maps 的依赖参数
    capi_maps.depargs = depargs
    # 获取函数的变量列表
    var = rout['vars']

    # 如果是模块函数,输出构建包装函数的消息
    if ismoduleroutine(rout):
        outmess('            Constructing wrapper function "%s.%s"...\n' %
                (rout['modulename'], rout['name']))
    else:
        outmess('        Constructing wrapper function "%s"...\n' % (rout['name']))

    # 根据函数签名构建路由映射
    vrd = capi_maps.routsign2map(rout)
    rd = dictappend({}, vrd)

    # 根据规则集对函数进行处理
    for r in rout_rules:
        # 如果规则包含 '_check' 并且检查通过,或者规则没有 '_check',则应用规则
        if ('_check' in r and r['_check'](rout)) or ('_check' not in r):
            ar = applyrules(r, vrd, rout)
            rd = dictappend(rd, ar)

    # 处理函数的参数
    nth, nthk = 0, 0
    savevrd = {}
    for a in args:
        vrd = capi_maps.sign2map(a, var[a])
        if isintent_aux(var[a]):
            _rules = aux_rules
        else:
            _rules = arg_rules
            if not isintent_hide(var[a]):
                if not isoptional(var[a]):
                    nth = nth + 1
                    vrd['nth'] = repr(nth) + stnd[nth % 10] + ' argument'
                else:
                    nthk = nthk + 1
                    vrd['nth'] = repr(nthk) + stnd[nthk % 10] + ' keyword'
            else:
                vrd['nth'] = 'hidden'
        savevrd[a] = vrd
        for r in _rules:
            if '_depend' in r:
                continue
            if ('_check' in r and r['_check'](var[a])) or ('_check' not in r):
                ar = applyrules(r, vrd, var[a])
                rd = dictappend(rd, ar)
                if '_break' in r:
                    break

    # 处理依赖参数
    for a in depargs:
        if isintent_aux(var[a]):
            _rules = aux_rules
        else:
            _rules = arg_rules
        vrd = savevrd[a]
        for r in _rules:
            if '_depend' not in r:
                continue
            if ('_check' in r and r['_check'](var[a])) or ('_check' not in r):
                ar = applyrules(r, vrd, var[a])
                rd = dictappend(rd, ar)
                if '_break' in r:
                    break
        if 'check' in var[a]:
            for c in var[a]['check']:
                vrd['check'] = c
                ar = applyrules(check_rules, vrd, var[a])
                rd = dictappend(rd, ar)

    # 反转清理和关闭 Python 对象的列表(如果存在)
    if isinstance(rd['cleanupfrompyobj'], list):
        rd['cleanupfrompyobj'].reverse()
    if isinstance(rd['closepyobjfrom'], list):
        rd['closepyobjfrom'].reverse()

    # 构建函数的文档签名,并移除末尾逗号
    rd['docsignature'] = stripcomma(replace('#docsign##docsignopt##docsignxa#',
                                            {'docsign': rd['docsign'],
                                             'docsignopt': rd['docsignopt'],
                                             'docsignxa': rd['docsignxa']}))
    # 从 rd 字典中获取 'docsignxashort' 和 'docsignoptshort' 的值,替换字符串 "#docsignopt##docsignxa#" 中的占位符,
    # 使用 stripcomma 函数去除结果字符串中可能的逗号后返回。
    optargs = stripcomma(replace('#docsignopt##docsignxa#',
                                 {'docsignxa': rd['docsignxashort'],
                                  'docsignopt': rd['docsignoptshort']}
                                 ))
    
    # 如果 optargs 是空字符串,则从 rd 字典中获取 'docsign' 的值,替换字符串 "#docsign#" 的占位符,
    # 使用 stripcomma 函数去除结果字符串中可能的逗号后赋给 rd['docsignatureshort']。
    if optargs == '':
        rd['docsignatureshort'] = stripcomma(
            replace('#docsign#', {'docsign': rd['docsign']}))
    else:
        # 否则,替换字符串 "#docsign#[#docsignopt#]" 的占位符,使用 replace 函数,
        # 将结果赋给 rd['docsignatureshort']。
        rd['docsignatureshort'] = replace('#docsign#[#docsignopt#]',
                                          {'docsign': rd['docsign'],
                                           'docsignopt': optargs,
                                           })
    
    # 将 rd['docsignatureshort'] 中的下划线替换为 LaTeX 格式的转义序列 "\_",
    # 然后将其中的逗号替换为 ", ",并将结果赋给 rd['latexdocsignatureshort']。
    rd['latexdocsignatureshort'] = rd['docsignatureshort'].replace('_', '\\_')
    rd['latexdocsignatureshort'] = rd[
        'latexdocsignatureshort'].replace(',', ', ')
    
    # 从 rd 字典中获取 'callfortran' 和 'callfortranappend' 的值,替换字符串 "#callfortran##callfortranappend#" 的占位符,
    # 使用 stripcomma 函数去除结果字符串中可能的逗号后返回。
    cfs = stripcomma(replace('#callfortran##callfortranappend#', {
                     'callfortran': rd['callfortran'], 'callfortranappend': rd['callfortranappend']}))
    
    # 如果 rd['callfortranappend'] 的长度大于1,则从 rd 字典中获取 'callfortran' 和 'callfortranappend' 的值,
    # 替换字符串 "#callfortran# 0,#callfortranappend#" 的占位符,使用 stripcomma 函数去除结果字符串中可能的逗号后,
    # 将结果赋给 rd['callcompaqfortran'];否则,将前面计算得到的 cfs 赋给 rd['callcompaqfortran']。
    if len(rd['callfortranappend']) > 1:
        rd['callcompaqfortran'] = stripcomma(replace('#callfortran# 0,#callfortranappend#', {
                                             'callfortran': rd['callfortran'], 'callfortranappend': rd['callfortranappend']}))
    else:
        rd['callcompaqfortran'] = cfs
    
    # 将前面计算得到的 cfs 赋给 rd['callfortran']。
    rd['callfortran'] = cfs
    
    # 如果 rd['docreturn'] 是列表类型,则从 rd 字典中获取 'docreturn' 的值,替换字符串 "#docreturn#" 的占位符,
    # 使用 stripcomma 函数去除结果字符串中可能的逗号后,再在末尾加上等号"=",将结果赋给 rd['docreturn']。
    if isinstance(rd['docreturn'], list):
        rd['docreturn'] = stripcomma(
            replace('#docreturn#', {'docreturn': rd['docreturn']})) + ' = '
    
    # 初始化 rd['docstrsigns'] 和 rd['latexdocstrsigns'] 为空列表。
    rd['docstrsigns'] = []
    rd['latexdocstrsigns'] = []
    
    # 遍历包含字符串 'docstrreq', 'docstropt', 'docstrout', 'docstrcbs' 的列表,
    # 对于每个字符串 k:
    #   如果 rd 字典中存在 k,并且其值是列表类型,则将 rd[k] 中的元素追加到 rd['docstrsigns'] 中。
    #   将字符串 'latex' + k 赋给 k,并检查 rd 字典中是否存在这个键,如果存在且值是列表类型,
    #   则将 rd[k] 中的第一个元素追加到 rd['latexdocstrsigns'] 中,然后插入 LaTeX 描述环境的起始标记和结束标记之间的所有元素。
    for k in ['docstrreq', 'docstropt', 'docstrout', 'docstrcbs']:
        if k in rd and isinstance(rd[k], list):
            rd['docstrsigns'] = rd['docstrsigns'] + rd[k]
        k = 'latex' + k
        if k in rd and isinstance(rd[k], list):
            rd['latexdocstrsigns'] = rd['latexdocstrsigns'] + rd[k][0:1] +\
                ['\\begin{description}'] + rd[k][1:] +\
                ['\\end{description}']
    
    # 使用 routine_rules 中定义的规则对 rd 进行处理,将处理结果赋给 ar。
    ar = applyrules(routine_rules, rd)
    
    # 如果 rout 是模块化的例行程序,调用 outmess 函数输出格式化后的 ar['docshort'];
    # 否则,输出格式化后的 ar['docshort']。
    if ismoduleroutine(rout):
        outmess('              %s\n' % (ar['docshort']))
    else:
        outmess('          %s\n' % (ar['docshort']))
    
    # 返回 ar 和 wrap。
    return ar, wrap
# 导入内建的 os 模块
import os

# 导入内建的 re 模块(正则表达式)
import re

# 导入内建的 sys 模块
import sys

# 导入内建的 argparse 模块(命令行解析)
import argparse

# 导入内建的 itertools 模块(迭代工具)
import itertools

# 导入内建的 pathlib 模块(路径操作)
import pathlib

# 导入内建的 collections 模块
import collections

# 导入内建的 typing 模块
import typing

# 导入自定义模块或库 module
import module

.\numpy\numpy\f2py\src\fortranobject.c

/*
  This file implements: FortranObject, array_from_pyobj, copy_ND_array

  Author: Pearu Peterson <pearu@cens.ioc.ee>
  $Revision: 1.52 $
  $Date: 2005/07/11 07:44:20 $
*/

// 设置字典 dict 中名为 name 的项为 obj,若 obj 为 NULL 则打印错误信息并返回 -1
int
F2PyDict_SetItemString(PyObject *dict, char *name, PyObject *obj)
{
    if (obj == NULL) {
        fprintf(stderr, "Error loading %s\n", name);
        // 检查是否有 Python 异常发生,如果有则打印异常信息并清除异常状态
        if (PyErr_Occurred()) {
            PyErr_Print();
            PyErr_Clear();
        }
        return -1;
    }
    return PyDict_SetItemString(dict, name, obj);
}

/*
 * Python-only fallback for thread-local callback pointers
 */
// 更新线程本地回调指针
void *
F2PySwapThreadLocalCallbackPtr(char *key, void *ptr)
{
    PyObject *local_dict, *value;
    void *prev;

    // 获取当前线程状态的字典
    local_dict = PyThreadState_GetDict();
    if (local_dict == NULL) {
        // 如果获取失败,触发致命错误
        Py_FatalError(
                "F2PySwapThreadLocalCallbackPtr: PyThreadState_GetDict "
                "failed");
    }

    // 获取字典中 key 对应的值
    value = PyDict_GetItemString(local_dict, key);
    if (value != NULL) {
        // 如果找到值,将其转换为 void 指针类型
        prev = PyLong_AsVoidPtr(value);
        if (PyErr_Occurred()) {
            // 如果转换出错,触发致命错误
            Py_FatalError(
                    "F2PySwapThreadLocalCallbackPtr: PyLong_AsVoidPtr failed");
        }
    }
    else {
        prev = NULL;
    }

    // 将新的指针 ptr 转换为 PyLong 对象
    value = PyLong_FromVoidPtr((void *)ptr);
    if (value == NULL) {
        // 如果转换失败,触发致命错误
        Py_FatalError(
                "F2PySwapThreadLocalCallbackPtr: PyLong_FromVoidPtr failed");
    }

    // 将新的值设置回字典中
    if (PyDict_SetItemString(local_dict, key, value) != 0) {
        // 如果设置失败,触发致命错误
        Py_FatalError(
                "F2PySwapThreadLocalCallbackPtr: PyDict_SetItemString failed");
    }

    // 释放 PyLong 对象的引用
    Py_DECREF(value);

    // 返回先前的值 prev
    return prev;
}

// 获取线程本地回调指针
void *
F2PyGetThreadLocalCallbackPtr(char *key)
{
    PyObject *local_dict, *value;
    void *prev;

    // 获取当前线程状态的字典
    local_dict = PyThreadState_GetDict();
    if (local_dict == NULL) {
        // 如果获取失败,触发致命错误
        Py_FatalError(
                "F2PyGetThreadLocalCallbackPtr: PyThreadState_GetDict failed");
    }

    // 获取字典中 key 对应的值
    value = PyDict_GetItemString(local_dict, key);
    if (value != NULL) {
        // 如果找到值,将其转换为 void 指针类型
        prev = PyLong_AsVoidPtr(value);
        if (PyErr_Occurred()) {
            // 如果转换出错,触发致命错误
            Py_FatalError(
                    "F2PyGetThreadLocalCallbackPtr: PyLong_AsVoidPtr failed");
        }
    }
    else {
        prev = NULL;
    }

    // 返回先前的值 prev
    return prev;
}

// 根据给定的类型编号和元素大小,创建一个 PyArray_Descr 对象
static PyArray_Descr *
get_descr_from_type_and_elsize(const int type_num, const int elsize)  {
  // 根据类型编号创建 PyArray_Descr 对象
  PyArray_Descr * descr = PyArray_DescrFromType(type_num);
  if (type_num == NPY_STRING) {
    // 对于字符串类型,PyArray_DescrFromType 返回的描述符 elsize 为 0
    // 需要用 PyArray_DESCR_REPLACE 更新描述符并设置正确的 elsize
    PyArray_DESCR_REPLACE(descr);
    if (descr == NULL) {
      return NULL;
    }
    PyDataType_SET_ELSIZE(descr, elsize);
  }
  return descr;
}
    // 初始化指针变量,确保在后续使用中能正常赋值
    PyFortranObject *fp = NULL;
    // Python 对象指针,用于暂存临时变量
    PyObject *v = NULL;
    // 如果初始化函数不为空,则调用该函数进行 F90 模块对象的初始化
    if (init != NULL) { /* Initialize F90 module objects */
        (*(init))();
    }
    // 分配内存并创建 PyFortranObject 对象实例
    fp = PyObject_New(PyFortranObject, &PyFortran_Type);
    // 如果分配失败,则返回空指针
    if (fp == NULL) {
        return NULL;
    }
    // 创建一个新的空字典对象,并将其赋值给 fp 对象的 dict 属性
    if ((fp->dict = PyDict_New()) == NULL) {
        Py_DECREF(fp);
        return NULL;
    }
    // 初始化 fp 对象的长度属性为 0
    fp->len = 0;
    // 遍历 defs 数组,计算其中非空项的数量并赋值给 fp 对象的 len 属性
    while (defs[fp->len].name != NULL) {
        fp->len++;
    }
    // 如果 defs 数组长度为 0,则跳转到错误处理部分
    if (fp->len == 0) {
        goto fail;
    }
    // 将 defs 数组赋值给 fp 对象的 defs 属性
    fp->defs = defs;
    // 遍历 fp 对象的 defs 数组
    for (i = 0; i < fp->len; i++) {
        // 如果当前项的 rank 属性为 -1,表示是 Fortran 过程
        if (fp->defs[i].rank == -1) { /* Is Fortran routine */
            // 创建一个新的 Python 对象作为属性,并赋值给 v
            v = PyFortranObject_NewAsAttr(&(fp->defs[i]));
            // 如果创建失败,则跳转到错误处理部分
            if (v == NULL) {
                goto fail;
            }
            // 将 v 对象以字符串形式存入 fp 对象的 dict 属性
            PyDict_SetItemString(fp->dict, fp->defs[i].name, v);
            // 减少 v 对象的引用计数
            Py_XDECREF(v);
        }
        // 如果当前项的 data 属性不为空,表示是 Fortran 变量或数组(非 allocatable)
        else if ((fp->defs[i].data) != NULL) { /* Is Fortran variable or array (not allocatable) */
            // 根据类型和元素大小获取 PyArray_Descr 对象
            PyArray_Descr *descr = get_descr_from_type_and_elsize(fp->defs[i].type,
                                                                   fp->defs[i].elsize);
            // 如果获取失败,则跳转到错误处理部分
            if (descr == NULL) {
                goto fail;
            }
            // 根据描述符创建一个新的数组对象,并赋值给 v
            v = PyArray_NewFromDescr(&PyArray_Type, descr, fp->defs[i].rank,
                                     fp->defs[i].dims.d, NULL, fp->defs[i].data,
                                     NPY_ARRAY_FARRAY, NULL);
            // 如果创建失败,则减少描述符的引用计数,并跳转到错误处理部分
            if (v == NULL) {
                Py_DECREF(descr);
                goto fail;
            }
            // 将 v 对象以字符串形式存入 fp 对象的 dict 属性
            PyDict_SetItemString(fp->dict, fp->defs[i].name, v);
            // 减少 v 对象的引用计数
            Py_XDECREF(v);
        }
    }
    // 返回 fp 对象的 PyObject 指针类型
    return (PyObject *)fp;
fail:
    // 释放 fp 指针指向的对象,并返回 NULL,用于错误处理
    Py_XDECREF(fp);
    return NULL;
}

PyObject *
PyFortranObject_NewAsAttr(FortranDataDef *defs)
{ /* used for calling F90 module routines */
    // 初始化 fp 为 NULL
    PyFortranObject *fp = NULL;
    // 创建一个新的 PyFortranObject 对象,并将其类型设置为 PyFortran_Type
    fp = PyObject_New(PyFortranObject, &PyFortran_Type);
    // 如果创建对象失败,则调用失败处理块
    if (fp == NULL)
        return NULL;
    // 创建一个新的字典对象并将其赋值给 fp->dict
    if ((fp->dict = PyDict_New()) == NULL) {
        PyObject_Del(fp);
        // 如果创建字典失败,则调用失败处理块
        return NULL;
    }
    // 设置 fp->len1
    fp->len = 1;
    // 将 defs 赋值给 fp->defs
    fp->defs = defs;
    // 根据 defs->rank 的值设置 "__name__" 键在 fp->dict 中的值
    if (defs->rank == -1) {
      PyDict_SetItemString(fp->dict, "__name__", PyUnicode_FromFormat("function %s", defs->name));
    } else if (defs->rank == 0) {
      PyDict_SetItemString(fp->dict, "__name__", PyUnicode_FromFormat("scalar %s", defs->name));
    } else {
      PyDict_SetItemString(fp->dict, "__name__", PyUnicode_FromFormat("array %s", defs->name));
    }
    // 返回创建的 PyFortranObject 对象
    return (PyObject *)fp;
}

/* Fortran methods */

static void
fortran_dealloc(PyFortranObject *fp)
{
    // 释放 fp->dict 指向的对象
    Py_XDECREF(fp->dict);
    // 释放 fp 指向的对象
    PyObject_Del(fp);
}

/* Returns number of bytes consumed from buf, or -1 on error. */
static Py_ssize_t
format_def(char *buf, Py_ssize_t size, FortranDataDef def)
{
    char *p = buf;
    int i;
    npy_intp n;

    // 将数组格式的描述写入 buf 中,返回写入的字节数或者 -1 表示出错
    n = PyOS_snprintf(p, size, "array(%" NPY_INTP_FMT, def.dims.d[0]);
    if (n < 0 || n >= size) {
        return -1;
    }
    p += n;
    size -= n;

    // 循环将数组维度信息写入 buf 中
    for (i = 1; i < def.rank; i++) {
        n = PyOS_snprintf(p, size, ",%" NPY_INTP_FMT, def.dims.d[i]);
        if (n < 0 || n >= size) {
            return -1;
        }
        p += n;
        size -= n;
    }

    // 检查 buf 是否还有足够空间写入字符 ')'
    if (size <= 0) {
        return -1;
    }

    *p++ = ')';
    size--;

    // 如果 def.data 为 NULL,则在 buf 中添加字符串 ", not allocated"
    if (def.data == NULL) {
        static const char notalloc[] = ", not allocated";
        if ((size_t)size < sizeof(notalloc)) {
            return -1;
        }
        memcpy(p, notalloc, sizeof(notalloc));
        p += sizeof(notalloc);
        size -= sizeof(notalloc);
    }

    // 返回 buf 中的有效字节数
    return p - buf;
}

static PyObject *
fortran_doc(FortranDataDef def)
{
    char *buf, *p;
    PyObject *s = NULL;
    Py_ssize_t n, origsize, size = 100;

    // 根据 def.doc 的大小调整 size
    if (def.doc != NULL) {
        size += strlen(def.doc);
    }
    origsize = size;
    // 分配内存给 buf
    buf = p = (char *)PyMem_Malloc(size);
    if (buf == NULL) {
        return PyErr_NoMemory();
    }

    // 根据 def.rank 的值生成文档信息
    if (def.rank == -1) {
        if (def.doc) {
            // 将 def.doc 的内容复制到 buf 中
            n = strlen(def.doc);
            if (n > size) {
                goto fail;
            }
            memcpy(p, def.doc, n);
            p += n;
            size -= n;
        }
        else {
            // 如果没有 def.doc,则生成默认的描述信息
            n = PyOS_snprintf(p, size, "%s - no docs available", def.name);
            if (n < 0 || n >= size) {
                goto fail;
            }
            p += n;
            size -= n;
        }
    }
    else {
        // 根据数据类型定义创建一个 PyArray_Descr 结构体指针 d
        PyArray_Descr *d = PyArray_DescrFromType(def.type);
        // 使用 PyArray_Descr 结构体中的数据类型字符和定义的名称格式化输出到 p 所指向的 buf 中
        n = PyOS_snprintf(p, size, "%s : '%c'-", def.name, d->type);
        // 释放 PyArray_Descr 结构体指针 d
        Py_DECREF(d);
        // 如果格式化失败或者输出的字符数超过了 size,跳转到失败处理
        if (n < 0 || n >= size) {
            goto fail;
        }
        // 更新 p 的位置到新的可写入位置
        p += n;
        // 更新 size 的可用大小
        size -= n;

        // 如果 def.data 为 NULL,则调用 format_def 函数格式化输出到 p 所指向的 buf 中
        if (def.data == NULL) {
            n = format_def(p, size, def);
            if (n < 0) {
                goto fail;
            }
            p += n;
            size -= n;
        }
        // 如果 def.rank 大于 0,则调用 format_def 函数格式化输出到 p 所指向的 buf 中
        else if (def.rank > 0) {
            n = format_def(p, size, def);
            if (n < 0) {
                goto fail;
            }
            p += n;
            size -= n;
        }
        // 否则,输出字符串 "scalar" 到 p 所指向的 buf 中
        else {
            n = strlen("scalar");
            // 如果 size 小于需要写入的字符串长度,跳转到失败处理
            if (size < n) {
                goto fail;
            }
            // 将字符串 "scalar" 复制到 p 所指向的 buf 中
            memcpy(p, "scalar", n);
            // 更新 p 的位置到新的可写入位置
            p += n;
            // 更新 size 的可用大小
            size -= n;
        }
    }
    // 如果 size 小于等于 1,跳转到失败处理
    if (size <= 1) {
        goto fail;
    }
    // 在 p 所指向的 buf 末尾写入换行符 '\n'
    *p++ = '\n';
    // 更新 size 的可用大小
    size--;

    /* p 现在指向 buf 中字符串的末尾的下一个位置 */

    // 使用 buf 和 p 指向的字符串长度创建一个 Python Unicode 对象 s
    s = PyUnicode_FromStringAndSize(buf, p - buf);

    // 释放动态分配的 buf 内存
    PyMem_Free(buf);
    // 返回创建的 Python Unicode 对象 s
    return s;
fail:
    /* 打印错误消息到标准错误流,指出文档字符串长度超出允许的大小 */
    fprintf(stderr,
            "fortranobject.c: fortran_doc: len(p)=%zd>%zd=size:"
            " too long docstring required, increase size\n",
            p - buf, origsize);
    /* 释放之前分配的内存 */
    PyMem_Free(buf);
    /* 返回空指针,表示函数执行失败 */
    return NULL;
}

static FortranDataDef *save_def; /* 保存可分配数组的指针 */

static void
set_data(char *d, npy_intp *f)
{           /* 来自Fortran的回调函数 */
    /* 如果 f 不为零,说明在Fortran中 d 已经被分配了内存 */
    if (*f) /* In fortran f=allocated(d) */
        save_def->data = d;
    else
        save_def->data = NULL;
    /* printf("set_data: d=%p,f=%d\n",d,*f); */
}

static PyObject *
fortran_getattr(PyFortranObject *fp, char *name)
{
    int i, j, k, flag;
    /* 检查对象字典是否为空 */
    if (fp->dict != NULL) {
        /* 尝试从对象字典中获取名为 'name' 的项 */
        PyObject *v = _PyDict_GetItemStringWithError(fp->dict, name);
        /* 如果获取失败并且发生了错误,则返回空指针 */
        if (v == NULL && PyErr_Occurred()) {
            return NULL;
        }
        /* 如果获取成功,则增加引用计数并返回该项 */
        else if (v != NULL) {
            Py_INCREF(v);
            return v;
        }
    }
    /* 在对象的定义列表中查找与 'name' 匹配的项 */
    for (i = 0, j = 1; i < fp->len && (j = strcmp(name, fp->defs[i].name));
         i++)
        ;
    /* 如果找到了匹配项 */
    if (j == 0)
        /* 检查定义是否为F90可分配数组 */
        if (fp->defs[i].rank != -1) { /* F90 allocatable array */
            /* 如果回调函数不为空,则进行数组维度重置 */
            if (fp->defs[i].func == NULL)
                return NULL;
            /* 将数组维度设置为-1 */
            for (k = 0; k < fp->defs[i].rank; ++k) fp->defs[i].dims.d[k] = -1;
            /* 保存当前定义以便后续使用 */
            save_def = &fp->defs[i];
            /* 调用回调函数设置数据 */
            (*(fp->defs[i].func))(&fp->defs[i].rank, fp->defs[i].dims.d,
                                  set_data, &flag);
            /* 根据返回的标志检查数组状态 */
            if (flag == 2)
                k = fp->defs[i].rank + 1;
            else
                k = fp->defs[i].rank;
            /* 如果数据不为空,则创建新的PyArray对象 */
            if (fp->defs[i].data != NULL) { /* array is allocated */
                PyObject *v = PyArray_New(
                        &PyArray_Type, k, fp->defs[i].dims.d, fp->defs[i].type,
                        NULL, fp->defs[i].data, 0, NPY_ARRAY_FARRAY, NULL);
                /* 如果创建失败,则返回空指针 */
                if (v == NULL)
                    return NULL;
                /* 增加新对象的引用计数并返回 */
                /* Py_INCREF(v); */
                return v;
            }
            else { /* 如果数据为空,则返回Py_None */
                Py_RETURN_NONE;
            }
        }
    /* 如果 'name' 是特殊属性 '__dict__',返回对象字典 */
    if (strcmp(name, "__dict__") == 0) {
        Py_INCREF(fp->dict);
        return fp->dict;
    }
    /* 如果 'name' 是特殊属性 '__doc__' */
    if (strcmp(name, "__doc__") == 0) {
        /* 创建一个空的PyUnicode对象 */
        PyObject *s = PyUnicode_FromString(""), *s2, *s3;
        /* 遍历对象定义列表并获取其文档字符串 */
        for (i = 0; i < fp->len; i++) {
            s2 = fortran_doc(fp->defs[i]);
            s3 = PyUnicode_Concat(s, s2);
            Py_DECREF(s2);
            Py_DECREF(s);
            s = s3;
        }
        /* 将生成的文档字符串添加到对象字典中 */
        if (PyDict_SetItemString(fp->dict, name, s))
            return NULL;
        /* 返回文档字符串对象 */
        return s;
    }
    /* 如果 'name' 是特殊属性 '_cpointer',且对象只有一个定义 */
    if ((strcmp(name, "_cpointer") == 0) && (fp->len == 1)) {
        /* 创建一个F2PyCapsule对象 */
        PyObject *cobj =
                F2PyCapsule_FromVoidPtr((void *)(fp->defs[0].data), NULL);
        /* 将F2PyCapsule对象添加到对象字典中 */
        if (PyDict_SetItemString(fp->dict, name, cobj))
            return NULL;
        /* 返回F2PyCapsule对象 */
        return cobj;
    }
    /* 如果 'name' 不是以上任何特殊属性,则使用通用的属性获取方法 */
    PyObject *str, *ret;
    /* 从 'name' 创建一个PyUnicode对象 */
    str = PyUnicode_FromString(name);
    /* 调用通用的属性获取方法获取属性值 */
    ret = PyObject_GenericGetAttr((PyObject *)fp, str);
    /* 释放PyUnicode对象 */
    Py_DECREF(str);
    /* 返回获取的属性值 */
    return ret;
}

static int
# 设置 Fortran 对象的属性值
fortran_setattr(PyFortranObject *fp, char *name, PyObject *v)
{
    int i, j, flag;
    PyArrayObject *arr = NULL;

    // 遍历 fp 对象的定义列表,查找属性名为 name 的定义
    for (i = 0, j = 1; i < fp->len && (j = strcmp(name, fp->defs[i].name)); i++)
        ;

    // 如果找到属性名为 name 的定义
    if (j == 0) {
        // 如果属性是一个可分配的数组
        if (fp->defs[i].rank == -1) {
            // 抛出异常,不能覆盖 Fortran 程序
            PyErr_SetString(PyExc_AttributeError, "over-writing fortran routine");
            return -1; // 返回错误标志
        }
        // 如果属性有关联的函数
        if (fp->defs[i].func != NULL) { /* is allocatable array */
            npy_intp dims[F2PY_MAX_DIMS];
            int k;
            save_def = &fp->defs[i];

            // 如果新值 v 不是 Py_None,设置新值(如果需要重新分配,请参阅生成的 f2py 代码以获取更多细节)
            if (v != Py_None) {
                for (k = 0; k < fp->defs[i].rank; k++) dims[k] = -1;
                // 从 Python 对象 v 创建 NumPy 数组 arr
                if ((arr = array_from_pyobj(fp->defs[i].type, dims,
                                            fp->defs[i].rank, F2PY_INTENT_IN,
                                            v)) == NULL)
                    return -1;
                // 调用属性关联的函数来设置数据
                (*(fp->defs[i].func))(&fp->defs[i].rank, PyArray_DIMS(arr),
                                      set_data, &flag);
            }
            else { // 如果 v 是 Py_None,进行释放操作
                for (k = 0; k < fp->defs[i].rank; k++) dims[k] = 0;
                // 调用属性关联的函数来释放数据
                (*(fp->defs[i].func))(&fp->defs[i].rank, dims, set_data,
                                      &flag);
                for (k = 0; k < fp->defs[i].rank; k++) dims[k] = -1;
            }
            // 将维度信息复制回属性定义中
            memcpy(fp->defs[i].dims.d, dims,
                   fp->defs[i].rank * sizeof(npy_intp));
        }
        else { // 如果属性不是可分配的数组
            // 从 Python 对象 v 创建 NumPy 数组 arr
            if ((arr = array_from_pyobj(fp->defs[i].type, fp->defs[i].dims.d,
                                        fp->defs[i].rank, F2PY_INTENT_IN,
                                        v)) == NULL)
                return -1;
        }
        
        // 如果属性有关联的数据
        if (fp->defs[i].data != NULL) {
            // 计算 Fortran 数组的总大小
            npy_intp s = PyArray_MultiplyList(fp->defs[i].dims.d,
                                              PyArray_NDIM(arr));
            if (s == -1)
                s = PyArray_MultiplyList(PyArray_DIMS(arr), PyArray_NDIM(arr));
            // 将 Python 对象的数据复制到 Fortran 数组中
            if (s < 0 || (memcpy(fp->defs[i].data, PyArray_DATA(arr),
                                 s * PyArray_ITEMSIZE(arr))) == NULL) {
                if ((PyObject *)arr != v) {
                    Py_DECREF(arr);
                }
                return -1;
            }
            if ((PyObject *)arr != v) {
                Py_DECREF(arr);
            }
        }
        else
            return (fp->defs[i].func == NULL ? -1 : 0);
        return 0; // 操作成功
    }
    
    // 如果找不到属性名为 name 的定义,并且 fp 对象的字典为空,则创建一个新的字典
    if (fp->dict == NULL) {
        fp->dict = PyDict_New();
        if (fp->dict == NULL)
            return -1;
    }
    # 如果 v 为 NULL,则执行以下操作
    if (v == NULL) {
        # 尝试从字典 fp->dict 中删除键名为 name 的项
        int rv = PyDict_DelItemString(fp->dict, name);
        # 如果删除操作返回值 rv 小于 0,表示删除失败
        if (rv < 0)
            # 设置错误信息,指明试图删除不存在的 Fortran 属性
            PyErr_SetString(PyExc_AttributeError,
                            "delete non-existing fortran attribute");
        # 返回删除操作的结果值 rv
        return rv;
    }
    # 如果 v 不为 NULL,则执行以下操作
    else
        # 向字典 fp->dict 中设置键名为 name 的项的值为 v
        return PyDict_SetItemString(fp->dict, name, v);
static PyObject *
fortran_call(PyFortranObject *fp, PyObject *arg, PyObject *kw)
{
    int i = 0;
    /* 检查调用的 Fortran 对象是否为 Fortran 程序 */
    if (fp->defs[i].rank == -1) { /* is Fortran routine */
        if (fp->defs[i].func == NULL) {
            PyErr_Format(PyExc_RuntimeError, "no function to call");
            return NULL;
        }
        else if (fp->defs[i].data == NULL)
            /* 调用没有数据的 Fortran 子例程 */
            return (*((fortranfunc)(fp->defs[i].func)))((PyObject *)fp, arg,
                                                        kw, NULL);
        else
            /* 调用带有数据的 Fortran 子例程 */
            return (*((fortranfunc)(fp->defs[i].func)))(
                    (PyObject *)fp, arg, kw, (void *)fp->defs[i].data);
    }
    /* 如果不是 Fortran 对象,返回类型错误 */
    PyErr_Format(PyExc_TypeError, "this fortran object is not callable");
    return NULL;
}

static PyObject *
fortran_repr(PyFortranObject *fp)
{
    PyObject *name = NULL, *repr = NULL;
    // 获取对象的名称属性
    name = PyObject_GetAttrString((PyObject *)fp, "__name__");
    PyErr_Clear();
    // 根据对象名称生成对象的字符串表示
    if (name != NULL && PyUnicode_Check(name)) {
        repr = PyUnicode_FromFormat("<fortran %U>", name);
    }
    else {
        repr = PyUnicode_FromString("<fortran object>");
    }
    Py_XDECREF(name);
    return repr;
}

PyTypeObject PyFortran_Type = {
        PyVarObject_HEAD_INIT(NULL, 0).tp_name = "fortran",
        .tp_basicsize = sizeof(PyFortranObject),
        .tp_dealloc = (destructor)fortran_dealloc,
        .tp_getattr = (getattrfunc)fortran_getattr,
        .tp_setattr = (setattrfunc)fortran_setattr,
        .tp_repr = (reprfunc)fortran_repr,
        .tp_call = (ternaryfunc)fortran_call,
};

/************************* f2py_report_atexit *******************************/

#ifdef F2PY_REPORT_ATEXIT
static int passed_time = 0;
static int passed_counter = 0;
static int passed_call_time = 0;
static struct timeb start_time;
static struct timeb stop_time;
static struct timeb start_call_time;
static struct timeb stop_call_time;
static int cb_passed_time = 0;
static int cb_passed_counter = 0;
static int cb_passed_call_time = 0;
static struct timeb cb_start_time;
static struct timeb cb_stop_time;
static struct timeb cb_start_call_time;
static struct timeb cb_stop_call_time;

extern void
f2py_start_clock(void)
{
    // 开始计时
    ftime(&start_time);
}
extern void
f2py_start_call_clock(void)
{
    // 停止当前计时并开始调用计时
    f2py_stop_clock();
    ftime(&start_call_time);
}
extern void
f2py_stop_clock(void)
{
    // 停止计时并计算经过的时间
    ftime(&stop_time);
    passed_time += 1000 * (stop_time.time - start_time.time);
    passed_time += stop_time.millitm - start_time.millitm;
}
extern void
f2py_stop_call_clock(void)
{
    // 停止调用计时并计算经过的时间和调用次数
    ftime(&stop_call_time);
    passed_call_time += 1000 * (stop_call_time.time - start_call_time.time);
    passed_call_time += stop_call_time.millitm - start_call_time.millitm;
    passed_counter += 1;
    // 重新开始总计时
    f2py_start_clock();
}

extern void
f2py_cb_start_clock(void)
{
    // 开始回调计时
    ftime(&cb_start_time);
}
extern void
static int f2py_report_on_exit_been_here = 0;
extern void
f2py_report_on_exit(int exit_flag, void *name)
{
    // 如果已经在此函数中打印过一次报告,则只输出名称并返回
    if (f2py_report_on_exit_been_here) {
        fprintf(stderr, "             %s\n", (char *)name);
        return;
    }
    // 标记已经在此函数中打印过一次报告
    f2py_report_on_exit_been_here = 1;

    // 输出性能报告表头
    fprintf(stderr, "                      /-----------------------\\\n");
    fprintf(stderr, "                     < F2PY performance report >\n");
    fprintf(stderr, "                      \\-----------------------/\n");

    // 输出总体调用时间报告
    fprintf(stderr, "Overall time spent in ...\n");
    fprintf(stderr, "(a) wrapped (Fortran/C) functions           : %8d msec\n",
            passed_call_time);
    fprintf(stderr, "(b) f2py interface,           %6d calls  : %8d msec\n",
            passed_counter, passed_time);
    fprintf(stderr, "(c) call-back (Python) functions            : %8d msec\n",
            cb_passed_call_time);
    fprintf(stderr, "(d) f2py call-back interface, %6d calls  : %8d msec\n",
            cb_passed_counter, cb_passed_time);

    // 输出实际耗时较长的 wrapped 函数的时间
    fprintf(stderr,
            "(e) wrapped (Fortran/C) functions (actual) : %8d msec\n\n",
            passed_call_time - cb_passed_call_time - cb_passed_time);

    // 输出退出时的提示信息和模块名称
    fprintf(stderr,
            "Use -DF2PY_REPORT_ATEXIT_DISABLE to disable this message.\n");
    fprintf(stderr, "Exit status: %d\n", exit_flag);
    fprintf(stderr, "Modules    : %s\n", (char *)name);
}
/*
 * File: array_from_pyobj.c
 *
 * Description:
 * ------------
 * Provides array_from_pyobj function that returns a contiguous array
 * object with the given dimensions and required storage order, either
 * in row-major (C) or column-major (Fortran) order. The function
 * array_from_pyobj is very flexible about its Python object argument
 * that can be any number, list, tuple, or array.
 *
 * array_from_pyobj is used in f2py generated Python extension
 * modules.
 *
 * Author: Pearu Peterson <pearu@cens.ioc.ee>
 * Created: 13-16 January 2002
 * $Id: fortranobject.c,v 1.52 2005/07/11 07:44:20 pearu Exp $
 */

// 静态函数声明:检查并修正数组维度
static int check_and_fix_dimensions(const PyArrayObject* arr,
                                    const int rank,
                                    npy_intp *dims,
                                    const char *errmess);

// 查找第一个负维度的索引
static int
find_first_negative_dimension(const int rank, const npy_intp *dims)
{
    int i;
    for (i = 0; i < rank; ++i) {
        if (dims[i] < 0) {
            return i;
        }
    }
    return -1;
}

#ifdef DEBUG_COPY_ND_ARRAY
// 输出数组维度信息
void
dump_dims(int rank, npy_intp const *dims)
{
    int i;
    printf("[");
    for (i = 0; i < rank; ++i) {
        printf("%3" NPY_INTP_FMT, dims[i]);
    }
    printf("]\n");
}

// 输出数组属性信息
void
dump_attrs(const PyArrayObject *obj)
{
    const PyArrayObject_fields *arr = (const PyArrayObject_fields *)obj;
    int rank = PyArray_NDIM(arr);
    npy_intp size = PyArray_Size((PyObject *)arr);
    printf("\trank = %d, flags = %d, size = %" NPY_INTP_FMT "\n", rank,
           arr->flags, size);
    printf("\tstrides = ");
    dump_dims(rank, arr->strides);
    printf("\tdimensions = ");
    dump_dims(rank, arr->dimensions);
}
#endif

// 定义宏:交换两个数组对象的数据及属性
#define SWAPTYPE(a, b, t) \
    {                     \
        t c;              \
        c = (a);          \
        (a) = (b);        \
        (b) = c;          \
    }

// 交换两个数组对象的数据及属性
static int
swap_arrays(PyArrayObject *obj1, PyArrayObject *obj2)
{
    PyArrayObject_fields *arr1 = (PyArrayObject_fields *)obj1,
                         *arr2 = (PyArrayObject_fields *)obj2;
    SWAPTYPE(arr1->data, arr2->data, char *);
    SWAPTYPE(arr1->nd, arr2->nd, int);
    SWAPTYPE(arr1->dimensions, arr2->dimensions, npy_intp *);
    SWAPTYPE(arr1->strides, arr2->strides, npy_intp *);
    SWAPTYPE(arr1->base, arr2->base, PyObject *);
    SWAPTYPE(arr1->descr, arr2->descr, PyArray_Descr *);
    SWAPTYPE(arr1->flags, arr2->flags, int);
    /* SWAPTYPE(arr1->weakreflist,arr2->weakreflist,PyObject*); */
    return 0;
}

// 定义宏:判断数组对象是否与指定数据类型兼容
#define ARRAY_ISCOMPATIBLE(arr,type_num)                                \
    ((PyArray_ISINTEGER(arr) && PyTypeNum_ISINTEGER(type_num)) ||     \
     (PyArray_ISFLOAT(arr) && PyTypeNum_ISFLOAT(type_num)) ||         \
     (PyArray_ISCOMPLEX(arr) && PyTypeNum_ISCOMPLEX(type_num)) ||     \
     (PyArray_ISBOOL(arr) && PyTypeNum_ISBOOL(type_num)) ||           \
     (PyArray_ISSTRING(arr) && PyTypeNum_ISSTRING(type_num)))

// 获取对象的元素大小
static int
get_elsize(PyObject *obj) {
  /*
    /* 
    get_elsize 函数根据输入的 Python 对象确定数组元素的大小。如果成功,则返回元素大小,否则返回 -1。

    支持的输入类型包括:numpy.ndarray, bytes, str, tuple, list.
    */

    if (PyArray_Check(obj)) {
        // 如果输入对象是 numpy 数组,则返回数组元素的大小
        return PyArray_ITEMSIZE((PyArrayObject *)obj);
    } else if (PyBytes_Check(obj)) {
        // 如果输入对象是字节对象(bytes),则返回其大小
        return PyBytes_GET_SIZE(obj);
    } else if (PyUnicode_Check(obj)) {
        // 如果输入对象是 Unicode 对象(str),则返回其长度
        return PyUnicode_GET_LENGTH(obj);
    } else if (PySequence_Check(obj)) {
        // 如果输入对象是序列(tuplelist)
        PyObject* fast = PySequence_Fast(obj, "f2py:fortranobject.c:get_elsize");
        if (fast != NULL) {
            // 获取序列的长度
            Py_ssize_t i, n = PySequence_Fast_GET_SIZE(fast);
            int sz, elsize = 0;
            // 遍历序列中的每个元素
            for (i=0; i<n; i++) {
                // 递归调用 get_elsize 函数,获取每个元素的大小
                sz = get_elsize(PySequence_Fast_GET_ITEM(fast, i) /* borrowed */);
                // 更新 elsize 为最大的元素大小
                if (sz > elsize) {
                    elsize = sz;
                }
            }
            Py_DECREF(fast);
            return elsize;
        }
    }
    // 如果无法确定输入对象的类型或者其他情况,返回 -1
    return -1;
    /*
    */
extern PyArrayObject *
ndarray_from_pyobj(const int type_num,
                   const int elsize_,
                   npy_intp *dims,
                   const int rank,
                   const int intent,
                   PyObject *obj,
                   const char *errmess) {
    /*
     * 从 Python 对象中创建一个具有指定元素类型和形状的数组,并考虑数组的使用意图。
     *
     * - 元素类型由 type_num 和 elsize 定义
     * - 形状由 dims 和 rank 定义
     *
     * ndarray_from_pyobj 用于将 Python 对象参数转换为具有给定类型和形状的 numpy ndarray,
     * 以便将数据传递给与 Fortran 或 C 函数交互的场合。
     *
     * 如果 errmess 不为 NULL,则包含在此函数内部触发异常的错误消息前缀。
     *
     * 负的 elsize 值表示 elsize 在运行时从 Python 对象中确定。
     *
     * 字符串类型 (type_num == NPY_STRING) 没有固定的元素大小,默认情况下类型对象将其设置为 0。
     * 因此,对于字符串类型,必须使用 elsize 参数。对于其他类型,elsize 值被忽略。
     *
     * NumPy 将固定宽度字符串的类型定义为 dtype('S<width>')。此外,还有 dtype('c'),显示为 dtype('S1')
     * (它们具有相同的 type_num 值),但实际上不同(.char 属性为 'S''c')。
     *
     * 在 Fortran 中,字符数组和字符串是不同的概念。Fortran 类型、NumPy dtypes 和 type_num-elsize 对之间的关系定义如下:
     *
     * character*5 foo     | dtype('S5')  | elsize=5, shape=()
     * character(5) foo    | dtype('S1')  | elsize=1, shape=(5)
     * character*5 foo(n)  | dtype('S5')  | elsize=5, shape=(n,)
     * character(5) foo(n) | dtype('S1')  | elsize=1, shape=(5, n)
     * character*(*) foo   | dtype('S')   | elsize=-1, shape=()
     *
     * 引用计数注意事项
     * -----------------
     *
     * 如果调用者将数组返回给 Python,则必须使用 Py_BuildValue("N",arr)。否则,如果 obj!=arr,则调用者必须调用 Py_DECREF(arr)。
     *
     * 使用意图(intent)(缓存、输出等)的注意事项
     * ------------------------------------------
     *
     * 当返回 intent(cache) 数组时,不要期望数据是正确的。
     *
     */
    char mess[F2PY_MESSAGE_BUFFER_SIZE]; // 用于存储错误消息的缓冲区
    PyArrayObject *arr = NULL; // 初始化一个空的 PyArrayObject 对象
    int elsize = (elsize_ < 0 ? get_elsize(obj) : elsize_); // 确定元素大小,如果 elsize_ 小于 0,则从 obj 中获取

    // 如果 elsize 仍然小于 0,表示无法确定元素大小
    if (elsize < 0) {
      // 如果有错误消息,将其复制到 mess 中
      if (errmess != NULL) {
        strcpy(mess, errmess);
      }
      // 将错误消息格式化添加到 mess 中
      sprintf(mess + strlen(mess),
              " -- failed to determine element size from %s",
              Py_TYPE(obj)->tp_name);
      // 设置 Python 异常并返回空指针
      PyErr_SetString(PyExc_SystemError, mess);
      return NULL;
    }
    PyArray_Descr * descr = get_descr_from_type_and_elsize(type_num, elsize);  // 根据数据类型和元素大小获取描述符,返回新引用
    if (descr == NULL) {
      return NULL;
    }
    elsize = PyDataType_ELSIZE(descr);  // 获取描述符中的元素大小
    if ((intent & F2PY_INTENT_HIDE)
        || ((intent & F2PY_INTENT_CACHE) && (obj == Py_None))
        || ((intent & F2PY_OPTIONAL) && (obj == Py_None))
        ) {
        /* intent(cache), optional, intent(hide) */
        int ineg = find_first_negative_dimension(rank, dims);  // 查找维度数组中第一个负数的索引
        if (ineg >= 0) {
            int i;
            strcpy(mess, "failed to create intent(cache|hide)|optional array"
                   "-- must have defined dimensions but got (");
            for(i = 0; i < rank; ++i)
                sprintf(mess + strlen(mess), "%" NPY_INTP_FMT ",", dims[i]);  // 格式化拼接维度信息到错误消息中
            strcat(mess, ")");
            PyErr_SetString(PyExc_ValueError, mess);  // 设置值错误异常并传入错误消息
            Py_DECREF(descr);  // 减少描述符的引用计数
            return NULL;
        }
        arr = (PyArrayObject *)                                      \
          PyArray_NewFromDescr(&PyArray_Type, descr, rank, dims,
                               NULL, NULL, !(intent & F2PY_INTENT_C), NULL);  // 根据描述符创建新的数组对象
        if (arr == NULL) {
          Py_DECREF(descr);  // 创建失败时释放描述符的引用
          return NULL;
        }
        if (PyArray_ITEMSIZE(arr) != elsize) {
          strcpy(mess, "failed to create intent(cache|hide)|optional array");
          sprintf(mess+strlen(mess)," -- expected elsize=%d got %" NPY_INTP_FMT, elsize, (npy_intp)PyArray_ITEMSIZE(arr));  // 格式化拼接预期和实际的元素大小到错误消息中
          PyErr_SetString(PyExc_ValueError,mess);  // 设置值错误异常并传入错误消息
          Py_DECREF(arr);  // 减少数组对象的引用计数
          return NULL;
        }
        if (!(intent & F2PY_INTENT_CACHE)) {
          PyArray_FILLWBYTE(arr, 0);  // 如果没有缓存意图,则用零填充数组
        }
        return arr;  // 返回创建的数组对象
    }

    if ((intent & F2PY_INTENT_INOUT) || (intent & F2PY_INTENT_INPLACE) ||
        (intent & F2PY_INTENT_CACHE)) {
        PyErr_Format(PyExc_TypeError,
                     "failed to initialize intent(inout|inplace|cache) "
                     "array, input '%s' object is not an array",
                     Py_TYPE(obj)->tp_name);  // 格式化错误消息,指示输入对象不是数组
        Py_DECREF(descr);  // 减少描述符的引用计数
        return NULL;
    }
    {
        // 执行F2PY_REPORT_ON_ARRAY_COPY_FROMANY宏,可能生成有关数组复制的报告
        F2PY_REPORT_ON_ARRAY_COPY_FROMANY;
        // 将给定的Python对象转换为NumPy数组对象
        arr = (PyArrayObject *)PyArray_FromAny(
                obj, descr, 0, 0,
                // 根据intent标志选择数组存储方式:C顺序或Fortran顺序,并强制类型转换
                ((intent & F2PY_INTENT_C) ? NPY_ARRAY_CARRAY
                                          : NPY_ARRAY_FARRAY) |
                        NPY_ARRAY_FORCECAST,
                NULL);
        // 警告:在NPY_STRING的情况下,PyArray_FromAny可能会重置descr->elsize,
        // 例如dtype('S0')可能变成dtype('S1')。
        if (arr == NULL) {
            // 如果转换失败,释放描述符对象并返回NULL
            Py_DECREF(descr);
            return NULL;
        }
        // 如果数组类型不是NPY_STRING且数组项大小不等于期望的elsize
        if (type_num != NPY_STRING && PyArray_ITEMSIZE(arr) != elsize) {
            // 这是内部的健全性检查:在函数开头已将elsize设置为descr->elsize。
            // 设置错误信息说明预期的elsize和实际获取的数组项大小不匹配
            strcpy(mess, "failed to initialize intent(in) array");
            sprintf(mess + strlen(mess),
                    " -- expected elsize=%d got %" NPY_INTP_FMT, elsize,
                    (npy_intp)PyArray_ITEMSIZE(arr));
            // 设置异常,并释放数组对象后返回NULL
            PyErr_SetString(PyExc_ValueError, mess);
            Py_DECREF(arr);
            return NULL;
        }
        // 检查并修正数组的维度,如果出错则释放数组对象并返回NULL
        if (check_and_fix_dimensions(arr, rank, dims, errmess)) {
            Py_DECREF(arr);
            return NULL;
        }
        // 如果以上检查都通过,返回转换后的NumPy数组对象
        return arr;
    }
}

extern PyArrayObject *
array_from_pyobj(const int type_num,
                 npy_intp *dims,
                 const int rank,
                 const int intent,
                 PyObject *obj) {
  /*
    Same as ndarray_from_pyobj but with elsize determined from type,
    if possible. Provided for backward compatibility.
   */
  // 根据给定的类型编号获取对应的数组描述符
  PyArray_Descr* descr = PyArray_DescrFromType(type_num);
  // 获取描述符的元素大小
  int elsize = PyDataType_ELSIZE(descr);
  // 减少描述符的引用计数,防止内存泄漏
  Py_DECREF(descr);
  // 调用ndarray_from_pyobj函数创建并返回NumPy数组对象
  return ndarray_from_pyobj(type_num, elsize, dims, rank, intent, obj, NULL);
}

/*****************************************/
/* Helper functions for array_from_pyobj */
/*****************************************/

static int
check_and_fix_dimensions(const PyArrayObject* arr, const int rank,
                         npy_intp *dims, const char *errmess)
{
    /*
     * This function fills in blanks (that are -1's) in dims list using
     * the dimensions from arr. It also checks that non-blank dims will
     * match with the corresponding values in arr dimensions.
     *
     * Returns 0 if the function is successful.
     *
     * If an error condition is detected, an exception is set and 1 is
     * returned.
     */
    // 定义错误消息的字符数组
    char mess[F2PY_MESSAGE_BUFFER_SIZE];
    // 计算arr的总元素数
    const npy_intp arr_size =
            (PyArray_NDIM(arr)) ? PyArray_Size((PyObject *)arr) : 1;
#ifdef DEBUG_COPY_ND_ARRAY
    // 调试模式下打印数组的属性
    dump_attrs(arr);
    printf("check_and_fix_dimensions:init: dims=");
    // 调试模式下打印维度信息
    dump_dims(rank, dims);
#endif
    # 如果要求的维度rank大于数组arr的维度数,进行以下处理:[1,2] -> [[1],[2]]; 1 -> [[1]]
    # 这段代码用于调整数组的维度匹配要求的rank
    if (rank > PyArray_NDIM(arr)) { /* [1,2] -> [[1],[2]]; 1 -> [[1]]  */
        npy_intp new_size = 1;  // 初始化新数组的总大小为1
        int free_axe = -1;  // 自由轴的索引,初始化为-1表示无自由轴
        int i;
        npy_intp d;
        // 填充dims中为-1或0的维度,并检查维度是否符合要求,计算新的总大小
        for (i = 0; i < PyArray_NDIM(arr); ++i) {
            d = PyArray_DIM(arr, i);  // 获取数组arr在第i维的大小
            if (dims[i] >= 0) {  // 如果dims中第i维要求大于等于0
                if (d > 1 && dims[i] != d) {  // 如果数组arr在第i维的大小大于1且与要求的dims[i]不符
                    PyErr_Format(
                            PyExc_ValueError,
                            "%d-th dimension must be fixed to %" NPY_INTP_FMT
                            " but got %" NPY_INTP_FMT "\n",
                            i, dims[i], d);
                    return 1;  // 报错并返回1,表示处理失败
                }
                if (!dims[i])
                    dims[i] = 1;  // 如果dims[i]为0,则设置为1
            }
            else {
                dims[i] = d ? d : 1;  // 如果dims[i]小于0,则设为数组arr在第i维的大小,如果为0则设为1
            }
            new_size *= dims[i];  // 计算新数组的总大小
        }
        // 对于超出数组arr维度数的维度rank,进行额外处理
        for (i = PyArray_NDIM(arr); i < rank; ++i)
            if (dims[i] > 1) {  // 如果dims中第i维要求大于1
                PyErr_Format(PyExc_ValueError,
                             "%d-th dimension must be %" NPY_INTP_FMT
                             " but got 0 (not defined).\n",
                             i, dims[i]);
                return 1;  // 报错并返回1,表示处理失败
            }
            else if (free_axe < 0)
                free_axe = i;  // 记录第一个自由轴的索引
            else
                dims[i] = 1;  // 其余维度设为1
        // 如果存在自由轴free_axe
        if (free_axe >= 0) {
            dims[free_axe] = arr_size / new_size;  // 计算自由轴的大小
            new_size *= dims[free_axe];  // 更新新数组的总大小
        }
        // 如果新的总大小与原数组的大小不匹配,报错
        if (new_size != arr_size) {
            PyErr_Format(PyExc_ValueError,
                         "unexpected array size: new_size=%" NPY_INTP_FMT
                         ", got array with arr_size=%" NPY_INTP_FMT
                         " (maybe too many free indices)\n",
                         new_size, arr_size);
            return 1;  // 报错并返回1,表示处理失败
        }
    }
    # 如果排名(维度数)等于数组的维度数
    else if (rank == PyArray_NDIM(arr)) {
        # 计算新的数组大小为1
        npy_intp new_size = 1;
        int i;
        npy_intp d;
        # 遍历数组的每一个维度
        for (i = 0; i < rank; ++i) {
            # 获取数组在第i维度上的大小
            d = PyArray_DIM(arr, i);
            # 如果给定的维度值大于等于0
            if (dims[i] >= 0) {
                # 如果数组的维度大于1且不等于给定的维度值
                if (d > 1 && d != dims[i]) {
                    # 如果错误消息不为空,则复制到mess中
                    if (errmess != NULL) {
                        strcpy(mess, errmess);
                    }
                    # 将错误消息格式化加入到mess中
                    sprintf(mess + strlen(mess),
                            " -- %d-th dimension must be fixed to %"
                            NPY_INTP_FMT " but got %" NPY_INTP_FMT,
                            i, dims[i], d);
                    # 设置Python异常并返回1表示出错
                    PyErr_SetString(PyExc_ValueError, mess);
                    return 1;
                }
                # 如果给定的维度值为0,则将其设为1
                if (!dims[i])
                    dims[i] = 1;
            }
            else
                # 否则,将数组当前维度大小赋值给给定的维度值
                dims[i] = d;
            # 计算新的数组大小
            new_size *= dims[i];
        }
        # 如果新的数组大小与原数组大小不一致
        if (new_size != arr_size) {
            # 抛出格式化的异常,指出意外的数组大小
            PyErr_Format(PyExc_ValueError,
                         "unexpected array size: new_size=%" NPY_INTP_FMT
                         ", got array with arr_size=%" NPY_INTP_FMT "\n",
                         new_size, arr_size);
            # 返回1表示出错
            return 1;
        }
    }
    }
#ifdef DEBUG_COPY_ND_ARRAY
    // 如果定义了 DEBUG_COPY_ND_ARRAY 宏,则输出调试信息
    printf("check_and_fix_dimensions:end: dims=");
    // 打印调试信息,显示维度信息
    dump_dims(rank, dims);
#endif
    // 返回操作成功的标志
    return 0;
}

/* End of file: array_from_pyobj.c */

/************************* copy_ND_array *******************************/

extern int
copy_ND_array(const PyArrayObject *arr, PyArrayObject *out)
{
    // 报告在从 arr 复制数组到 out 时的状态
    F2PY_REPORT_ON_ARRAY_COPY_FROMARR;
    // 调用 NumPy 提供的函数将 arr 复制到 out 中
    return PyArray_CopyInto(out, (PyArrayObject *)arr);
}

/********************* Various utility functions ***********************/

extern int
f2py_describe(PyObject *obj, char *buf) {
  /*
    Write the description of a Python object to buf. The caller must
    provide buffer with size sufficient to write the description.

    Return 1 on success.
  */
  // 本地缓冲区,用于存储描述信息
  char localbuf[F2PY_MESSAGE_BUFFER_SIZE];
  // 根据不同类型的 Python 对象生成描述信息
  if (PyBytes_Check(obj)) {
    sprintf(localbuf, "%d-%s", (npy_int)PyBytes_GET_SIZE(obj), Py_TYPE(obj)->tp_name);
  } else if (PyUnicode_Check(obj)) {
    sprintf(localbuf, "%d-%s", (npy_int)PyUnicode_GET_LENGTH(obj), Py_TYPE(obj)->tp_name);
  } else if (PyArray_CheckScalar(obj)) {
    PyArrayObject* arr = (PyArrayObject*)obj;
    sprintf(localbuf, "%c%" NPY_INTP_FMT "-%s-scalar", PyArray_DESCR(arr)->kind, PyArray_ITEMSIZE(arr), Py_TYPE(obj)->tp_name);
  } else if (PyArray_Check(obj)) {
    int i;
    PyArrayObject* arr = (PyArrayObject*)obj;
    strcpy(localbuf, "(");
    for (i=0; i<PyArray_NDIM(arr); i++) {
      if (i) {
        strcat(localbuf, " ");
      }
      sprintf(localbuf + strlen(localbuf), "%" NPY_INTP_FMT ",", PyArray_DIM(arr, i));
    }
    sprintf(localbuf + strlen(localbuf), ")-%c%" NPY_INTP_FMT "-%s", PyArray_DESCR(arr)->kind, PyArray_ITEMSIZE(arr), Py_TYPE(obj)->tp_name);
  } else if (PySequence_Check(obj)) {
    sprintf(localbuf, "%d-%s", (npy_int)PySequence_Length(obj), Py_TYPE(obj)->tp_name);
  } else {
    sprintf(localbuf, "%s instance", Py_TYPE(obj)->tp_name);
  }
  // 将本地缓冲区的内容复制到目标缓冲区 buf 中
  strcpy(buf, localbuf);
  // 返回成功标志
  return 1;
}

extern npy_intp
f2py_size_impl(PyArrayObject* var, ...)
{
  // 初始大小为 0
  npy_intp sz = 0;
  npy_intp dim;
  npy_intp rank;
  va_list argp;
  va_start(argp, var);
  // 获取可变参数中的第一个参数
  dim = va_arg(argp, npy_int);
  if (dim==-1)
    {
      // 如果 dim 为 -1,则返回数组的总元素个数
      sz = PyArray_SIZE(var);
    }
  else
    {
      // 否则,获取数组的维度数
      rank = PyArray_NDIM(var);
      // 如果 dim 在有效范围内,则返回对应维度的大小
      if (dim>=1 && dim<=rank)
        sz = PyArray_DIM(var, dim-1);
      else
        // 否则输出错误信息并返回 0
        fprintf(stderr, "f2py_size: 2nd argument value=%" NPY_INTP_FMT
                " fails to satisfy 1<=value<=%" NPY_INTP_FMT
                ". Result will be 0.\n", dim, rank);
    }
  va_end(argp);
  // 返回计算出的大小
  return sz;
}

/*********************************************/
/* Compatibility functions for Python >= 3.0 */
/*********************************************/

PyObject *
F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *))
{
    // 创建一个 Python Capsule 对象
    PyObject *ret = PyCapsule_New(ptr, NULL, dtor);
    // 如果创建失败,清空错误信息
    if (ret == NULL) {
        PyErr_Clear();
    }
    // 返回创建的 Python 对象
    return ret;
}

void *
F2PyCapsule_AsVoidPtr(PyObject *obj)
{
    # 使用 PyCapsule_GetPointer 函数从 Python Capsule 对象中获取指针
    void *ret = PyCapsule_GetPointer(obj, NULL);
    
    # 检查获取的指针是否为空
    if (ret == NULL) {
        # 如果为空指针,则清除当前的 Python 异常状态
        PyErr_Clear();
    }
    
    # 返回获取到的指针
    return ret;
}

int
F2PyCapsule_Check(PyObject *ptr)
{
    // 检查给定指针是否是一个 PyCapsule 对象
    return PyCapsule_CheckExact(ptr);
}

#ifdef __cplusplus
}
#endif
/************************* EOF fortranobject.c *******************************/

.\numpy\numpy\f2py\src\fortranobject.h

#ifndef Py_FORTRANOBJECT_H
#define Py_FORTRANOBJECT_H
#ifdef __cplusplus
extern "C" {
#endif

#include <Python.h>

#ifndef NPY_NO_DEPRECATED_API
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#endif

#ifdef FORTRANOBJECT_C
#define NO_IMPORT_ARRAY
#endif

#define PY_ARRAY_UNIQUE_SYMBOL _npy_f2py_ARRAY_API
#include "numpy/arrayobject.h"
#include "numpy/npy_3kcompat.h"

#ifdef F2PY_REPORT_ATEXIT
#include <sys/timeb.h>
// clang-format off
extern void f2py_start_clock(void);
extern void f2py_stop_clock(void);
extern void f2py_start_call_clock(void);
extern void f2py_stop_call_clock(void);
extern void f2py_cb_start_clock(void);
extern void f2py_cb_stop_clock(void);
extern void f2py_cb_start_call_clock(void);
extern void f2py_cb_stop_call_clock(void);
extern void f2py_report_on_exit(int, void *);
// clang-format on
#endif

#ifdef DMALLOC
#include "dmalloc.h"
#endif

/* Fortran object interface */

/*
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12

PyFortranObject represents various Fortran objects:
Fortran (module) routines, COMMON blocks, module data.

Author: Pearu Peterson <pearu@cens.ioc.ee>
*/

#define F2PY_MAX_DIMS 40
#define F2PY_MESSAGE_BUFFER_SIZE 300  // Increase on "stack smashing detected"

typedef void (*f2py_set_data_func)(char *, npy_intp *);
typedef void (*f2py_void_func)(void);
typedef void (*f2py_init_func)(int *, npy_intp *, f2py_set_data_func, int *);

/*typedef void* (*f2py_c_func)(void*,...);*/

typedef void *(*f2pycfunc)(void);

typedef struct {
    char *name; /* attribute (array||routine) name */
    int rank;   /* array rank, 0 for scalar, max is F2PY_MAX_DIMS,
                   || rank=-1 for Fortran routine */
    struct {
        npy_intp d[F2PY_MAX_DIMS];
    } dims;              /* dimensions of the array, || not used */
    int type;            /* PyArray_<type> || not used */
    int elsize;                /* Element size || not used */
    char *data;          /* pointer to array || Fortran routine */
    f2py_init_func func; /* initialization function for
                            allocatable arrays:
                            func(&rank,dims,set_ptr_func,name,len(name))
                            || C/API wrapper for Fortran routine */
    char *doc;           /* documentation string; only recommended
                            for routines. */
} FortranDataDef;

typedef struct {
    PyObject_HEAD
    int len;              /* Number of attributes */
    FortranDataDef *defs; /* An array of FortranDataDef's */
    PyObject *dict;       /* Fortran object attribute dictionary */
} PyFortranObject;

#define PyFortran_Check(op) (Py_TYPE(op) == &PyFortran_Type)
#define PyFortran_Check1(op) (0 == strcmp(Py_TYPE(op)->tp_name, "fortran"))

extern PyTypeObject PyFortran_Type;
extern int
F2PyDict_SetItemString(PyObject *dict, char *name, PyObject *obj);
extern PyObject *
PyFortranObject_New(FortranDataDef *defs, f2py_void_func init);
extern PyObject *

#endif  // Py_FORTRANOBJECT_H
/* 定义一个函数原型,用于创建一个 PyFortranObject 作为属性 */
PyFortranObject_NewAsAttr(FortranDataDef *defs);

/* 
   创建一个 Python Capsule 对象,将一个 void 指针封装起来,并指定一个析构函数。
   这个 Capsule 对象可以用来在 Python 和 C 之间传递指针。
*/
PyObject *
F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *));

/* 
   从 Python Capsule 对象中获取 void 指针。
   这个函数用于从 Python 中获取在 Capsule 中封装的原始指针。
*/
void *
F2PyCapsule_AsVoidPtr(PyObject *obj);

/* 
   检查一个对象是否是 F2Py Capsule 类型。
   这个宏用于确定一个对象是否是有效的 Capsule 对象。
*/
int
F2PyCapsule_Check(PyObject *ptr);

/* 
   在多线程环境中,用于设置线程本地的回调指针。
*/
extern void *
F2PySwapThreadLocalCallbackPtr(char *key, void *ptr);

/* 
   在多线程环境中,用于获取线程本地的回调指针。
*/
extern void *
F2PyGetThreadLocalCallbackPtr(char *key);

/* 定义一个宏,用于检查一个数组是否是 C 连续存储的 */
#define ISCONTIGUOUS(m) (PyArray_FLAGS(m) & NPY_ARRAY_C_CONTIGUOUS)

/* 定义一系列常量,用于描述参数的意图 */
#define F2PY_INTENT_IN 1
#define F2PY_INTENT_INOUT 2
#define F2PY_INTENT_OUT 4
#define F2PY_INTENT_HIDE 8
#define F2PY_INTENT_CACHE 16
#define F2PY_INTENT_COPY 32
#define F2PY_INTENT_C 64
#define F2PY_OPTIONAL 128
#define F2PY_INTENT_INPLACE 256
#define F2PY_INTENT_ALIGNED4 512
#define F2PY_INTENT_ALIGNED8 1024
#define F2PY_INTENT_ALIGNED16 2048

/* 
   定义一系列宏,用于检查数组的对齐要求
*/
#define F2PY_ALIGN4(intent) (intent & F2PY_INTENT_ALIGNED4)
#define F2PY_ALIGN8(intent) (intent & F2PY_INTENT_ALIGNED8)
#define F2PY_ALIGN16(intent) (intent & F2PY_INTENT_ALIGNED16)

/* 
   获取指定意图下的数组对齐大小
*/
#define F2PY_GET_ALIGNMENT(intent) \
    (F2PY_ALIGN4(intent)           \
             ? 4                   \
             : (F2PY_ALIGN8(intent) ? 8 : (F2PY_ALIGN16(intent) ? 16 : 1)))

/* 
   检查数组是否满足指定的对齐要求
*/
#define F2PY_CHECK_ALIGNMENT(arr, intent) \
    ARRAY_ISALIGNED(arr, F2PY_GET_ALIGNMENT(intent))

/* 
   检查数组是否兼容字符类型
*/
#define F2PY_ARRAY_IS_CHARACTER_COMPATIBLE(arr) ((PyArray_DESCR(arr)->type_num == NPY_STRING && PyArray_ITEMSIZE(arr) >= 1) \
                                                 || PyArray_DESCR(arr)->type_num == NPY_UINT8)

/* 
   检查数组是否是 Unicode 类型
*/
#define F2PY_IS_UNICODE_ARRAY(arr) (PyArray_DESCR(arr)->type_num == NPY_UNICODE)

/* 
   定义一个函数原型,用于从 Python 对象创建一个多维数组
*/
extern PyArrayObject *
ndarray_from_pyobj(const int type_num, const int elsize_, npy_intp *dims,
                   const int rank, const int intent, PyObject *obj,
                   const char *errmess);

/* 
   定义一个函数原型,用于从 Python 对象创建一个一维数组
*/
extern PyArrayObject *
array_from_pyobj(const int type_num, npy_intp *dims, const int rank,
                 const int intent, PyObject *obj);

/* 
   定义一个函数,用于复制一个多维数组
*/
extern int
copy_ND_array(const PyArrayObject *in, PyArrayObject *out);

#ifdef DEBUG_COPY_ND_ARRAY
/* 
   如果定义了 DEBUG_COPY_ND_ARRAY,定义一个函数原型,用于打印数组的属性
*/
extern void
dump_attrs(const PyArrayObject *arr);
#endif

/* 
   定义一个函数原型,用于描述一个 Python 对象
*/
extern int f2py_describe(PyObject *obj, char *buf);

/* 
   以下是一系列宏和函数,用于在签名文件表达式中使用的实用工具。
   可以参考 signature-file.rst 获取更多文档信息。
*/

/* 
   宏,用于获取数组元素的大小
*/
#define f2py_itemsize(var) (PyArray_ITEMSIZE(capi_ ## var ## _as_array))

/* 
   宏,用于获取数组的大小
*/
#define f2py_size(var, ...) f2py_size_impl((PyArrayObject *)(capi_ ## var ## _as_array), ## __VA_ARGS__, -1)

/* 
   宏,用于获取数组的秩(维度数量)
*/
#define f2py_rank(var) var ## _Rank

/* 
   宏,用于获取数组的指定维度的大小
*/
#define f2py_shape(var,dim) var ## _Dims[dim]

/* 
   宏,用于获取数组的第一维度大小
*/
#define f2py_len(var) f2py_shape(var,0)

/* 
   宏,用于获取数组的逆序排列的维度大小
*/
#define f2py_fshape(var,dim) f2py_shape(var,rank(var)-dim-1)

/* 
   宏,用于获取适用于字符串长度的数组大小
*/
#define f2py_flen(var) f2py_fshape(var,0)

/* 
   宏,用于获取对象的字符串长度
*/
#define f2py_slen(var) capi_ ## var ## _len

/* 
   定义一个函数原型,用于获取数组的大小
*/
extern npy_intp f2py_size_impl(PyArrayObject* var, ...);