You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cython封装C库项目结构与setup.py配置问题咨询

C/Cython项目最优结构与setup.py配置方案

最优项目结构

project/
├── src/
│   ├── myproject/          # 主Python包,统一管理所有模块
│   │   ├── __init__.py
│   │   ├── c_lib/          # 独立存放C源码与头文件
│   │   │   ├── __init__.py  # 空文件,标记为Python子包
│   │   │   ├── c1.c
│   │   │   ├── c1.h
│   │   │   ├── c2.c
│   │   │   └── c2.h
│   │   └── cython_modules/ # 存放Cython模块与声明文件
│   │       ├── __init__.py
│   │       ├── cython1.pyx
│   │       ├── cython1.pxd
│   │       ├── cython2.pyx
│   │       ├── cython2.pxd
│   │       └── c_includes.pxd  # 集中管理C函数的Cython声明
└── setup.py

正确的setup.py配置

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

# 1. 将C源码编译为独立静态库Extension
c_lib_sources = [
    "src/myproject/c_lib/c1.c",
    "src/myproject/c_lib/c2.c"
]

c_lib_ext = Extension(
    "myproject.c_lib._c_lib",
    sources=c_lib_sources,
    include_dirs=["src/myproject/c_lib"],
    extra_compile_args=["-fPIC"],  # 生成位置无关代码,支持动态链接
)

# 2. 定义Cython模块Extension,统一链接C静态库
cython_extensions = []
for module_name in ["cython1", "cython2"]:
    ext = Extension(
        f"myproject.cython_modules.{module_name}",
        sources=[f"src/myproject/cython_modules/{module_name}.pyx"],
        include_dirs=["src/myproject/c_lib"],
        # 链接编译好的C静态库
        extra_link_args=[c_lib_ext.outputs[0]] if hasattr(c_lib_ext, 'outputs') else []
    )
    cython_extensions.append(ext)

# 3. 执行打包配置
setup(
    name="myproject",
    package_dir={"": "src"},  # 指定源码根目录为src
    packages=["myproject", "myproject.c_lib", "myproject.cython_modules"],
    include_package_data=True,
    package_data={
        "myproject.c_lib": ["*.h"],  # 打包头文件供外部项目引用
        "myproject.cython_modules": ["*.pxd"]  # 打包pxd文件支持cimport
    },
    ext_modules=cythonize([c_lib_ext] + cython_extensions),
    zip_safe=False  # 动态库无法安全压缩,禁用该选项
)

核心问题的解决细节

1. 消除cimport时找不到C文件的问题

  • 彻底放弃在.pxd中直接引用.c文件的写法,改为引用.h头文件。
  • 在c_includes.pxd中集中声明C函数:
    cdef extern from "c1.h":
        void c1_function()
    
    cdef extern from "c2.h":
        void c2_function()
    
  • 其他Cython模块通过cimport myproject.cython_modules.c_includes引入声明,cimport只会依赖.pxd和.h文件,不再受C源码路径影响。

2. 解决符号缺失问题

  • 将所有C源码编译为一个独立的静态库,所有Cython模块统一链接这个库,确保C函数的符号被正确注入到最终的共享库中,避免运行时找不到符号。

3. 解决C函数重复声明/定义问题

  • 只编译一次C源码生成静态库,所有Cython模块共享这个库,从根源避免重复编译C文件导致的符号冲突。
  • C文件间的相互引用(如c2.c包含c1.h)会在编译C静态库时自动处理,无需额外配置。

内容的提问来源于stack exchange,提问作者Ipse Lium

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 04:07:03