【问题标题】:Cython cimport from another directoryCython cimport 从另一个目录
【发布时间】:2019-06-28 18:59:52
【问题描述】:

对于背景,我已阅读以下问题: https://github.com/cython/cython/wiki/PackageHierarchy

https://cython.readthedocs.io/en/latest/src/userguide/sharing_declarations.html#search-paths-for-definition-files

Cython cimport cannot find .pxd module

How do you get cimport to work in Cython?

Error compiling Cython file: pxd not found in package

问题是这样的。我曾经有大量的 C、C++ 和 Cython 都放在一个目录中并且编译得很好。现在,我将代码分成 2 个目录:

  1. 模块“cpysim”的 C/C++/Cython 源代码
  2. 另一个模块“dut”的 C/C++/Cython 代码

基本原理是模块cpysim 将被多次重用,而模块dut 将因项目而异。最后一个问题是模块cpysim 中的一个文件只能参考模块dut 中的一个文件进行编译,这就是给我带来问题的原因。

需要明确的是,当所有内容都在一个目录中时,一切都可以正常编译。这就是现在的样子。

<root>
  -- __init__.py
  -- cpysim
    -- __init__.py
    -- __init__.pxd
    -- sim_core.cpp
    -- sim_core.hpp
    -- sim_core.pxd
    ....
    wiretypes.pyx
    <other sources>
  -- dut
    -- wire_names.def
    -- setup_dut.py
    <other sources>

目标

dut 目录编译wiretypes.pyx(从位于dut 目录中的setup_dut.py)。

试试 1

此导入在wiretypes.pyx 中给我带来了麻烦

from libcpp cimport bool
from sim_core cimport sigtype_t  # <-- this one
....

这是setup_dut.py的相关内容

inc_dirs = ['./', '../', '../cpysim/', '../build', '../dSFMT-src-2.2.3', '../build/include']
....
      Extension("wiretypes",
                ["../cpysim/wiretypes.pyx"],
                language="c++",
                libraries=["cpysim", "ethphy"],
                include_dirs=inc_dirs,
                library_dirs=lib_dirs,
                extra_compile_args=compile_args,
                extra_link_args=link_args),
....
ext = cythonize(extensions,
                gdb_debug=True,
                compiler_directives={'language_level': '3'})

setup(ext_modules=ext,
      cmdclass={'build_ext': build_ext},
      include_dirs=[np.get_include()])

为什么我认为这应该起作用:根据文档,指定包含 sim_core.pxd 标头的包含路径就足够了。例如,cimport numpy as np 在设置 include_dirs=[np.get_include()] 时有效,np.get_include() 只是吐出一条路径。所以,在inc_dirs 中,我输入了../cpysim。当我编译时,我得到了

Error compiling Cython file:
------------------------------------------------------------
...
"""
Cython header defining a net.
"""

from libcpp cimport bool
from sim_core cimport sigtype_t
^
------------------------------------------------------------

/Users/colinww/system-model/cpysim/wiretypes.pyx:8:0: 'sim_core.pxd' not found

试试 2

我想也许我需要将cpysim 目录视为一个模块。所以我添加了__init__.py,并将wiretypes.pyx中的导入改为:

from libcpp cimport bool
cimport cpysim.sim_core as sim_core
Error compiling Cython file:
------------------------------------------------------------
...
"""
Cython header defining a net.
"""

from libcpp cimport bool
cimport cpysim.sim_core as sim_core
       ^
------------------------------------------------------------

/Users/colinww/system-model/cpysim/wiretypes.pyx:8:8: 'cpysim/sim_core.pxd' not found

所以现在我很茫然。我不明白为什么我的第一次尝试没有成功,我知道包含目录正在正确传递,因为还有许多其他需要找到并正确编译的标头。

我认为cimport 工作原理的一些基本方面是我缺少的。

【问题讨论】:

  • 更奇怪的行为:指定include_dirs=['../cpysim']cpysim_dir = os.path.abspath(os.path.join(os.getcwd(), '../cpysim')) sys.path.insert(0, cpysim_dir) 具有不同的行为...为什么将目录放在系统路径与包含路径上会有所不同?

标签: cython cythonize


【解决方案1】:

您似乎会将包含与...包含混淆。

构建 Cython 扩展是一个两步过程:

  1. 从 pyx 文件生成 C-souce 文件,使用 cythonize 函数和必要 pxd 文件的路径作为 Cython 编译器的包含路径(准确地说是 cythonize 不' t 直接调用 Cython 编译器 - 它稍后会在执行 setup 时发生,但为了这个答案,我们假设 cythonized = 调用 Cython 编译器)

  2. 当调用setup-function 时,使用所需的头文件(*.h 文件,例如 numpy's)的包含路径从生成的 C 文件生成一个 so 文件(或其他文件)。

如果将include_dirs 添加到Extension 会发生什么? Cython 编译器或 C 编译器使用它吗?

Cython 使用传递给 cythonize-function 的包含目录,在你的情况下它什么都不是(导致 [.]),即它必须更改为

ext = cythonize(extensions, include_path=[<path1>, <path2>], ...)

但是,Cython 也使用 sys.path 来搜索 pxd 文件 - 因此设置 sys.path 可能是一种解决方法(这有点 hacky,因为每次操作 sys.path) - 在这种情况下,顺序包括:include_directoriessys.pathCython/Includes(至少在大多数 current versions 中)。


有趣的是,如果使用 setuptools 而没有显式调用 cythonize,那么 Cython 和 C 编译器都会使用 include_dirs,即:

from setuptools import setup, Extension

extensions = [Extension("foo", ["foo.pyx"], include_dirs=[<path1>, <path2>])]
setup(name="foo", ext_modules=extensions)

导致path1path2 都被 Cython 和 C 编译器使用。

但是,我不确定是否可以推荐上述设置include_path 的解决方案:它之所以有效,只是因为setuptools uses(另见thatdeprecatedold_build_ext,它设置了@987654351 @here:

...
for source in cython_sources:
    ...
    options = CompilationOptions(...
            include_path = includes,  # HERE WE GO!
            ...)
      result = cython_compile(source, options=options,
                                full_module_name=module_name)

【讨论】:

  • 感谢您清除此问题,完美运行。我可以发誓那不是我读到的,所以我回到了文档,确实这正是它所说的,include_dirsinclude_path 之间的区别被清楚地解释了。我只是感到困惑,因为这两个命令(setupcythonize)发生了很多事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-05
  • 2017-11-24
  • 2014-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多