首页 > 编程问答 >cimport 包装 C 库的 cython 模块

cimport 包装 C 库的 cython 模块

时间:2024-07-20 22:56:19浏览次数:10  
标签:python c cython

我有这种 C/cython 项目:

project/
├── src/
│   └── modules/
│       ├── cython1.pyx
│       ├── cython1.pxd
│       ├── cython2.pyx
│       ├── cython2.pxd
│       ├── includes/
│       │   ├── c1.h
│       │   ├── c1.c
│       │   ├── c2.h
│       │   ├── c2.c
│       └── ...
└── setup.py

用这个 setup.py

filenames = ['cython1', 'cython2']
extensions = [Extension(name=f"modules.{name}", 
                        sources=[f"modules/{name}.pyx"],
                        include_dirs=["modules/includes", ]) for name in filenames]

setup(
    ext_modules=cythonize(extensions),
    packages=['project'],
    include_package_data=True,
    package_data = {
        'module': ['*.pxd', '*.so'],
    },
    ]
)

我有几个问题。

在 pxd 文件中,我使用 C 文件中的定义,如下所示: cdef extern from "includes/c1.c" 并且项目编译并且运行没有任何问题。 当我尝试 cimport module1 在另一个上下文中时,出现致命错误:找不到“c1.c”文件。

当我在 pxd 文件中设置 cdef extern from "includes/c1.h" 时,项目可以编译,但执行时会出现错误 (| ||:C 文件中的函数不在命名空间中)。 symbol not found in flat namespace 我尝试将相应的 C 文件添加到每个模块的源列表中 (

),然后收到一条消息,指出 C 函数已声明多次。事实上,我在不同的 cython 模块中使用 C 函数。而且,不同的c/h文件相互交互(例如“c2.c”中可以有一个 sources=[f"modules/{name}.pyx", "c1.c"] )。 #include "c1.h" 最后,我无法管理它,也无法弄清楚了解如何构建项目以便其正常运行并且也可以导入。我从论坛了解到,一种解决方案可能是将我的 C 文件预编译为共享库,但我无法让此过程直接在

中工作。 setup.py 构建项目和编写的最佳方法是什么

setup.py 编辑:

我将项目的结构:

和setup.py更改为:

project/
├── src/
│   ├── modules_clib/
│   │   ├── c1.h
│   │   ├── c1.c
│   │   ├── c2.h
│   │   └── c2.c
│   │
│   └── modules/
│       ├── cython1.pyx
│       ├── cython1.pxd
│       ├── cython2.pyx
│       ├── cython2.pxd
│       └── includes.pxd
└── setup.py

所有

filenames = ['cython1', 'cython2']
extensions = [Extension(name=f"modules.{name}", 
                        sources=[f"./src/modules/{name}.pyx"],
                        include_dirs=["./src/modules_clib", ]) for name in filenames]

setup(
    ext_modules=cythonize(extensions),
    packages=['project'],
    include_package_data=True,
    packages=['modules_clib', 'modules'],
    package_dir={'': 'src'},
    package_data={'modules_clib': ['*.c', '*.h'],
                  'modules': ['*.pxd', '*.so']},
    ]
)

现在都聚集在 cdef extern from "../modules_clib/c1.c" 文件中。在 includes.pxd 文件中,我 moduleX.pyx 来自 cimport 的所有必需的C函数。我现在也可以 modules.includes cimport modules.includes 从另一个项目/笔记本使用C函数,因为 cimport modules.cythonX 被复制到 libc 目录中。我不知道 site-packages 直接复制到 libc 目录中是不是好事,但确实有效。 site-packages 但是,我还是被迫直接使用C文件。使用标头仍然会导致

据我了解,当使用 C 文件时,cython 直接使用使用它们的 symbol not found in flat namespace 文件来编译它们,如果使用标头则不是这样。 *.pyx files that use them, which is not the case if headers are used.


好的,让我们来解决一下你关于在 Cython 项目中打包 C 库的问题。你碰到的问题在跨平台 C/Cython 集成中很常见,而且理解这些问题的解决方案对于创建良好的项目结构至关重要。

分析你的问题

  1. “找不到文件”错误: 当你在一个 Cython 模块( .pyx ) 中 cimport 另一个模块时出现这个错误,表明 Cython 编译器找不到被 cimport 模块所依赖的 C 头文件( .h )。这是因为 Cython 需要这些头文件来理解 C 函数和类型的定义。

  2. “符号未在平面命名空间中找到”错误: 这个错误表明,虽然 Cython 找到了头文件,但它在链接阶段无法解析对 C 函数的实际引用。这通常是因为 C 代码没有被正确编译成库,或者没有在链接过程中被正确链接。

推荐的解决方案和最佳实践

以下是一种构建 Cython 项目的结构化方法,该方法可以解决你遇到的问题,并提供更好的可维护性:

project/
├── src/
│   ├── modules_clib/        # 你的 C 库
│   │   ├── c1.h
│   │   ├── c1.c
│   │   ├── c2.h
│   │   └── c2.c
│   └── modules/            # 你的 Cython 模块
│       ├── cython1.pyx
│       ├── cython1.pxd
│       ├── cython2.pyx
│       ├── cython2.pxd
│       └── includes.pxd      # 用于外部声明的中心位置
└── setup.py

setup.py

from setuptools import setup, Extension
from Cython.Build import cythonize

# 首先编译 C 库
clib_extension = Extension(
    "modules_clib",
    sources=[
        "./src/modules_clib/c1.c",
        "./src/modules_clib/c2.c",
    ],
    include_dirs=["./src/modules_clib"],  # 确保包含目录
)

# 然后编译 Cython 模块
cython_extensions = [
    Extension(
        "modules.cython1",
        sources=["./src/modules/cython1.pyx"],
        include_dirs=["./src/modules_clib"],  # 用于 C 头文件
        libraries=["modules_clib"],  # 链接到 C 库
        library_dirs=["./src"],  # 库的路径
    ),
    Extension(
        "modules.cython2",
        sources=["./src/modules/cython2.pyx"],
        include_dirs=["./src/modules_clib"],
        libraries=["modules_clib"],
        library_dirs=["./src"],
    ),
]

setup(
    name="your_project_name",
    ext_modules=cythonize(cython_extensions) + [clib_extension],  # 同时编译
    packages=["modules"],
    package_dir={"": "src"},
    zip_safe=False,  # 对于包含 .so 文件很重要
)

解释

  1. 分离的 C 库: 将 C 代码组织到一个单独的库( modules_clib )中,可以实现更清晰的代码结构和更容易的维护。

  2. 显式库编译和链接: setup.py 中,首先使用 Extension 为 C 代码创建一个扩展模块( clib_extension )。这将在构建过程中编译你的 C 代码。然后,在你的 Cython 模块的 Extension 中,使用 libraries library_dirs 参数链接到这个编译好的 C 库。

  3. 包含目录: 确保 include_dirs 包含了 C 头文件的位置,以便 Cython 和 C 编译器都能找到它们。

  4. zip_safe=False 为了让 Python 能够加载你的扩展模块( .so 文件),请在 setup() 中设置 zip_safe=False

includes.pxd

这个文件可以作为所有 C 函数和类型的中心声明点。

cdef extern from "modules_clib/c1.h":
    # c1.h 中的函数和类型声明

cdef extern from "modules_clib/c2.h":
    # c2.h 中的函数和类型声明

然后,你可以在你的 Cython 模块中使用 cimport modules.includes 来访问这些声明。

使用这个结构的好处

  • 模块化: C 代码和 Cython 代码被清晰地分开。
  • 可维护性: 更改 C 代码或 Cython 代码的影响被最小化。
  • 可重用性: C 库可以很容易地在其他项目中重用。

通过遵循这些步骤,你可以建立一个更稳固、更可维护的 Cython 项目,该项目可以正确地与你的 C 代码集成。

标签:python,c,cython
From: 78727843

相关文章

  • SearchBar组件
    文章目录1.概念介绍2.使用方法3.代码与效果3.1示例代码3.2运行效果4.内容总结我们在上一章回中介绍了"Material3中的IconButton"相关的内容,本章回中将介绍SearchBar组件.闲话休提,让我们一起TalkFlutter吧。1.概念介绍我们在本章回中介绍的SearchBar是指......
  • 达梦数据库的系统视图v$dmwatcher
    达梦数据库的系统视图v$dmwatcher查询当前登录实例所对应的守护进程信息,注意一个守护进程可以同时守护多个组的实例,因此查询结果中部分字段(N_GROUP、SWITCH_COUNT)为守护进程的全局信息,并不是当前登录实例自身的守护信息。在DMDSC集群环境中,只显示控制守护进程的信息。另......
  • 一元二次方程c++题目
    描述利用公式x1=(-b+sqrt(b*b-4*a*c))/(2*a),x2=(-b-sqrt(b*b-4*a*c))/(2*a)求一元二次方程ax2+bx+c=0的根,其中a不等于0。输入输入一行,包含三个浮点数a,b,c(它们之间以一个空格分开),分别表示方程ax?+bx+c=0的系数。输出输出一行,表示方程的解。若b2=4*a*c,则两个实根相......
  • C#新语法
    要脑子有什么用,它只会想你。--zhu顶级语句(C#9.0)1、直接在C#文件中编写入口方法的代码,不用类,不用Main。经典写法仍然支持,可以反编译了解一下。2、同一个项目中只能有一个文件具有顶级语句。namespacep4_1{classProgram{staticvoidMain(string[]args)......
  • Python:如何通过请求帖子对评论进行投票?
    我对评论进行投票的代码无法正常工作。它返回一个http500错误。我有一个使用用户登录的Python程序,它应该自动对评论进行投票。我的代码如下:frombs4importBeautifulSoupimportrequestslogin_url="https://xxxxxxxxxxx/auth/login"login_url_post="http......
  • python_day7(补1)
    数据类型​ 之前为列表类型​ 插入一个元组的介绍 之后还有字典,三者区别为括号方式()[]{}元组类型(tuple)使用:先定义一个元组数据​ vegetable_tuple='(tomato','corn','cucumber','carrot','corn','pumpkin)'与列表类型格式很像,不过只能取不能改,需要特......
  • UE富文本框RichTextBlock的内容设置不同的字体颜色
    一、新建富文本样式行1.新建数据表 2.选择富文本样式行 二、添加样式 三、应用1.设置样式 2.包裹字体 四、效果展示 可根据自己的样式去包裹文本。......
  • Libtorch与QTOpenCV 和 Point Cloud Library 一起使用时出现错误
    我正在尝试在项目中使用libtorch、qt小部件、点云库(pcl)和opencv。对于这个项目,我使用的是cmake列表。问题是当我同时使用所有四个库时,libtorch会抛出错误。如果我使用libtorch、opencv和qt,一切正常,如果我使用pclqt和opencv,一切也都很好。我得到的错误列在下面:/libto......
  • Linux C++ 065-设计模式之组合模式
    LinuxC++065-设计模式之组合模式本节关键字:Linux、C++、设计模式、组合模式相关库函数:概念组合模式(CompositePattern),又叫做部分-整体模式,使得用户对单个对象和组合对象的使用具有一致性。它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理......
  • Linux C++ 066-设计模式之访问者模式
    LinuxC++066-设计模式之访问者模式本节关键字:Linux、C++、设计模式、访问者模式相关库函数:概念在访问者模式(VisitorPattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模......