从另一个目录导入 Cython cimport
Cython cimport from another directory
作为背景,我阅读了以下问题:
https://github.com/cython/cython/wiki/PackageHierarchy
How do you get cimport to work in Cython?
问题是这样的。我曾经有大量的 C、C++ 和 Cython 都放在一个目录中并且编译得很好。现在,我将代码分成 2 个目录:
- C/C++/模块的 Cython 源代码 "cpysim"
- C/C++/另一个模块的Cython代码"dut"
理由是模块 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
目录(从位于 dut
目录的 setup_dut.py
编译 wiretypes.pyx
。
尝试 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
header 的包含路径应该就足够了。比如设置include_dirs=[np.get_include()]
时cimport numpy as np
有效,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
所以现在我很茫然。我不明白为什么我的第一次尝试没有成功,我知道 include 目录被正确传递,因为还有许多其他 header 需要找到并正确编译。
我认为我缺少 cimport
工作原理的一些基本方面。
您似乎会将 includes 与 ... includes 混淆。
构建 Cython-extension 是一个两步过程:
从 pyx-file 生成 C-souce-file,使用 cythonize
-函数和必要的 pxd-files 的路径作为 include-paths Cython-compiler(准确地说 cythonize
不会直接调用 Cython-compiler - 它稍后会发生,当 setup
被执行时,但为了这个答案,我们假装cythonized
= 调用 Cython-compiler)
使用所需的头文件包含路径(*.h-files,例如 numpy 的)从生成的 C-file 中生成 so-file(或其他),当setup
-函数被调用。
如果将 include_dirs
添加到 Extension
会怎样?它是由 Cython-Compiler 还是 C-Compiler 使用的?
Cython 使用 include-directories 传递给 cythonize
函数,在您的情况下它什么都不是(结果为 [.]
),即它必须更改为
ext = cythonize(extensions, include_path=[<path1>, <path2>], ...)
但是,Cython 还使用 sys.path
来搜索 pxd
文件 - 因此设置 sys.path
可能是一种解决方法(这有点老套,因为对 sys.path
) - 在这种情况下,包含的顺序是:include_directories
、sys.path
、Cython/Includes
(至少在最current versions)。
有趣的是,如果使用没有显式调用 cythonize
的设置工具,那么 Cython- 和 C-compilers 都会使用 include_dirs
,即:
from setuptools import setup, Extension
extensions = [Extension("foo", ["foo.pyx"], include_dirs=[<path1>, <path2>])]
setup(name="foo", ext_modules=extensions)
导致 path1
和 path2
被 Cython 和 C-compilers 使用。
但是,我不确定是否可以推荐上述设置 include_path
的解决方案:它之所以有效,只是因为 setuptools
uses (also see that) deprecated old_build_ext
, which sets include_path
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)
作为背景,我阅读了以下问题: https://github.com/cython/cython/wiki/PackageHierarchy
How do you get cimport to work in Cython?
问题是这样的。我曾经有大量的 C、C++ 和 Cython 都放在一个目录中并且编译得很好。现在,我将代码分成 2 个目录:
- C/C++/模块的 Cython 源代码 "cpysim"
- C/C++/另一个模块的Cython代码"dut"
理由是模块 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
目录(从位于 dut
目录的 setup_dut.py
编译 wiretypes.pyx
。
尝试 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
header 的包含路径应该就足够了。比如设置include_dirs=[np.get_include()]
时cimport numpy as np
有效,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
所以现在我很茫然。我不明白为什么我的第一次尝试没有成功,我知道 include 目录被正确传递,因为还有许多其他 header 需要找到并正确编译。
我认为我缺少 cimport
工作原理的一些基本方面。
您似乎会将 includes 与 ... includes 混淆。
构建 Cython-extension 是一个两步过程:
从 pyx-file 生成 C-souce-file,使用
cythonize
-函数和必要的 pxd-files 的路径作为 include-paths Cython-compiler(准确地说cythonize
不会直接调用 Cython-compiler - 它稍后会发生,当setup
被执行时,但为了这个答案,我们假装cythonized
= 调用 Cython-compiler)使用所需的头文件包含路径(*.h-files,例如 numpy 的)从生成的 C-file 中生成 so-file(或其他),当
setup
-函数被调用。
如果将 include_dirs
添加到 Extension
会怎样?它是由 Cython-Compiler 还是 C-Compiler 使用的?
Cython 使用 include-directories 传递给 cythonize
函数,在您的情况下它什么都不是(结果为 [.]
),即它必须更改为
ext = cythonize(extensions, include_path=[<path1>, <path2>], ...)
但是,Cython 还使用 sys.path
来搜索 pxd
文件 - 因此设置 sys.path
可能是一种解决方法(这有点老套,因为对 sys.path
) - 在这种情况下,包含的顺序是:include_directories
、sys.path
、Cython/Includes
(至少在最current versions)。
有趣的是,如果使用没有显式调用 cythonize
的设置工具,那么 Cython- 和 C-compilers 都会使用 include_dirs
,即:
from setuptools import setup, Extension
extensions = [Extension("foo", ["foo.pyx"], include_dirs=[<path1>, <path2>])]
setup(name="foo", ext_modules=extensions)
导致 path1
和 path2
被 Cython 和 C-compilers 使用。
但是,我不确定是否可以推荐上述设置 include_path
的解决方案:它之所以有效,只是因为 setuptools
uses (also see that) deprecated old_build_ext
, which sets include_path
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)