【发布时间】:2021-07-30 17:22:13
【问题描述】:
我可以在 Cython 中使用 extern __declspec(dllimport) 吗?我正在尝试在 Windows 中包装 embree,但不确定是否可以在 Cython 中动态链接。
我阅读了this SO post,它非常适合直接更改 C/C++ 和头文件,但我不确定如何在 .pxd 文件中实现这一点。
例如,Embree 2.17.7 x64 标头 rtcore.h 将 RTCORE_API 定义为
#ifndef RTCORE_API
#if defined(_WIN32) && !defined(EMBREE_STATIC_LIB)
# define RTCORE_API extern "C" __declspec(dllimport)
#else
# define RTCORE_API extern "C"
#endif
#endif
但是,这些在pyembree pxd 文件rtcore.pxd 中使用它们的函数签名中被忽略了。这似乎与Cython docs 一致,该状态为
省略对 C 声明的任何特定于平台的扩展,例如 __declspec()
但是,即使我通过更改行将 pyembree setup.py 文件指向我下载的 embree DLL
ext.libraries = ["embree"]
到
ext.libraries = [""C:/Program Files/Intel/Embree v2.17.7 x64/bin/embree""]
我仍然收到 3 个链接错误:
mesh_construction.obj : error LNK2001: unresolved external symbol __imp_rtcMapBuffer
mesh_construction.obj : error LNK2001: unresolved external symbol __imp_rtcNewTriangleMesh
mesh_construction.obj : error LNK2001: unresolved external symbol __imp_rtcUnmapBuffer
build\lib.win-amd64-3.8\pyembree\mesh_construction.cp38-win_amd64.pyd : fatal error LNK1120: 3 unresolved externals
我从this SO post 和Microsoft docs 得知与__imp_ 相关的链接器错误是由于找不到DLL。但是,您可以在rtcore_geometry.h 中看到它已定义:
在rtcore_geometry.pxd 中定义:
唯一的区别是.pxd 文件的签名中不包含RTCORE_API。
有谁知道我该如何解决这个问题,以便 pyembree 构建?
编辑:还要注意,我已经加了
# distutils: language=c++
我所有的.pyx 和.pxd 文件。 This SO post 也被审核过,但并没有解决我的问题。
更新:将embree.lib文件添加到我的本地pyembree/embree2文件夹并将setup.py更新为
ext.libraries = ["pyembree/embree2/*"]
允许代码编译通过
py setup.py build_ext -i
但是,包不加载:
>>> import pyembree
>>> from pyembree import rtcore_scene
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: DLL load failed while importing rtcore_scene: The specified module could not be found.
我需要在setup.py 中定义“子包”吗?这是我目前的setup.py:
from setuptools import find_packages, setup
import numpy as np
from Cython.Build import cythonize
from Cython.Distutils import build_ext
include_path = [np.get_include()]
ext_modules = cythonize(
'pyembree/*.pyx',
language_level=3,
include_path=include_path)
for ext in ext_modules:
ext.include_dirs = include_path
ext.libraries = [
"pyembree/embree2/*",
]
setup(
name="pyembree",
version='0.1.6',
cmdclass = {"build_ext": build_ext},
ext_modules=ext_modules,
zip_safe=False,
packages=find_packages(),
include_package_data = True
)
目录结构如下(pyembree是我项目的.venv\lib\site-packages文件夹中的顶级文件夹):
pyembree
│ .authors.yml
│ .gitignore
│ .mailmap
│ AUTHORS
│ CHANGELOG.rst
│ LICENSE
│ MANIFEST.in
│ pyproject.toml
│ README.rst
│ setup.py
│
├───build
│ └───temp.win-amd64-3.8
│ └───Release
│ └───pyembree
│ mesh_construction.cp38-win_amd64.exp
│ mesh_construction.cp38-win_amd64.lib
│ mesh_construction.obj
│ rtcore.cp38-win_amd64.exp
│ rtcore.cp38-win_amd64.lib
│ rtcore.obj
│ rtcore_scene.cp38-win_amd64.exp
│ rtcore_scene.cp38-win_amd64.lib
│ rtcore_scene.obj
│ triangles.cp38-win_amd64.exp
│ triangles.cp38-win_amd64.lib
│ triangles.obj
│
├───pyembree
│ │ mesh_construction.cp38-win_amd64.pyd
│ │ mesh_construction.cpp
│ │ mesh_construction.h
│ │ mesh_construction.pyx
│ │ rtcore.cp38-win_amd64.pyd
│ │ rtcore.cpp
│ │ rtcore.pxd
│ │ rtcore.pyx
│ │ rtcore_geometry.pxd
│ │ rtcore_geometry_user.pxd
│ │ rtcore_ray.pxd
│ │ rtcore_scene.cp38-win_amd64.pyd
│ │ rtcore_scene.cpp
│ │ rtcore_scene.pxd
│ │ rtcore_scene.pyx
│ │ triangles.cp38-win_amd64.pyd
│ │ triangles.cpp
│ │ triangles.pyx
│ │ __init__.pxd
│ │ __init__.py
│ │
│ ├───embree2
│ │ embree.lib
│ │ rtcore.h
│ │ rtcore.isph
│ │ rtcore_builder.h
│ │ rtcore_geometry.h
│ │ rtcore_geometry.isph
│ │ rtcore_geometry_user.h
│ │ rtcore_geometry_user.isph
│ │ rtcore_ray.h
│ │ rtcore_ray.isph
│ │ rtcore_scene.h
│ │ rtcore_scene.isph
│ │ rtcore_version.h
│ │ tbb.lib
│ │ tbbmalloc.lib
│ │
│ └───__pycache__
│ __init__.cpython-38.pyc
│
└───tests
test_intersection.py
【问题讨论】:
-
.pxd 文件的内容是什么?你通常做
cdef extern from "header.h":。这将标头包含在 Cython 生成的 C 文件中。因此__declspec不相关,因为 Cython 不需要知道它,并且它在包含的标头中正确定义。 -
@Davidw 感谢您的帮助!
pxd文件位于此处:github.com/scopatz/pyembree/tree/master/pyembree。让我知道是否有更好的方法可以将其转移给您。 -
我不知道答案(抱歉),但我很确定 Cython 中的
__declspec不是你的问题 -
@DavidW 我实际上有一个更新。我会把它添加到问题中,如果你可以看看