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

基于Setuptools与CMake构建Python2/3双版本HDBSCAN C绑定扩展的库名冲突问题

解决同时构建HDBSCAN C实现的Python2/Python3绑定问题

针对你遇到的「无法同时构建Python2和Python3版本扩展、库名冲突」的问题,我们可以从CMake动态生成版本适配的库名和Setuptools多版本构建流程两个层面入手解决,以下是具体方案:

一、调整CMakeLists.txt,让库名随Python版本自动适配

核心思路是在CMake中检测当前构建目标的Python版本,分别设置符合Python2/3规范的库名和后缀,同时将两个版本的输出目录分开,避免覆盖:

# 清理可能存在的重复目标
if(TARGET PyHdbscan)
    unset(TARGET PyHdbscan)
endif()

# 构建Python2版本
find_package(Python2 REQUIRED COMPONENTS Development)
add_library(PyHdbscan_py2 SHARED
    # 填入你的C实现源文件,示例:
    hdbscan_core.c
    py_bindings.c
)
target_link_libraries(PyHdbscan_py2 PRIVATE Python2::Python)
# 设置Python2的库名和输出目录
set_target_properties(PyHdbscan_py2 PROPERTIES
    OUTPUT_NAME "PyHdbscan"
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/py2"
)

# 构建Python3版本
find_package(Python3 REQUIRED COMPONENTS Development)
add_library(PyHdbscan_py3 SHARED
    # 复用相同的源文件即可
    hdbscan_core.c
    py_bindings.c
)
target_link_libraries(PyHdbscan_py3 PRIVATE Python3::Python)
# 设置Python3的库名(自动带上SOABI后缀,比如cpython-38-x86_64-linux-gnu)和输出目录
set_target_properties(PyHdbscan_py3 PROPERTIES
    OUTPUT_NAME "PyHdbscan"
    SUFFIX ".${Python3_SOABI}.so"
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/py3"
)

这段代码会分别在build/py2和build/py3目录生成两个版本的库,完全避免命名冲突。

二、用Setuptools封装多版本构建流程

如果你希望通过setup.py一键触发两个版本的构建,可以自定义build_ext命令,分别调用CMake针对Python2和Python3构建:

from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext
import subprocess
import sys
import os

class DualVersionCMakeBuild(build_ext):
    def run(self):
        # 构建Python2版本(确保系统中python2命令可用)
        self._build_with_python("python2")
        # 构建Python3版本
        self._build_with_python(sys.executable)
        
    def _build_with_python(self, python_exec):
        # 为每个Python版本创建独立的临时构建目录
        build_temp = os.path.join(self.build_temp, os.path.basename(python_exec))
        os.makedirs(build_temp, exist_ok=True)
        
        cmake_args = [
            f"-DPython_EXECUTABLE={python_exec}",
            f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={self.build_lib}",
            "../"  # 假设CMakeLists.txt在项目根目录,根据实际路径调整
        ]
        
        # 执行CMake配置和构建
        subprocess.check_call(["cmake"] + cmake_args, cwd=build_temp)
        subprocess.check_call(["cmake", "--build", "."], cwd=build_temp)

# 定义扩展(实际源文件由CMake处理,这里留空即可)
ext = Extension("PyHdbscan", sources=[])

setup(
    name="PyHdbscan",
    version="0.1",
    ext_modules=[ext],
    cmdclass={"build_ext": DualVersionCMakeBuild}
)

简化方案:分两次调用setup.py

如果不需要一键构建,也可以直接分别调用两个版本的Python解释器执行构建:

# 构建Python2版本
python2 setup.py build_ext --inplace
# 构建Python3版本
python3 setup.py build_ext --inplace

此时只需要修改CMakeLists.txt为单版本适配的版本即可:

find_package(Python REQUIRED COMPONENTS Development)

add_library(PyHdbscan SHARED
    hdbscan_core.c
    py_bindings.c
)
target_link_libraries(PyHdbscan PRIVATE Python::Python)

# 根据Python版本设置后缀
execute_process(
    COMMAND ${Python_EXECUTABLE} -c "import sys; print(sys.version_info.major)"
    OUTPUT_VARIABLE PY_MAJOR
    OUTPUT_STRIP_TRAILING_WHITESPACE
)

if(PY_MAJOR EQUAL 3)
    set_target_properties(PyHdbscan PROPERTIES
        SUFFIX ".${Python_SOABI}.so"
    )
endif()

三、关键注意事项

  • 确保系统已安装Python2和Python3的开发包(比如Debian系的python-dev和python3-dev)
  • 如果你的C绑定代码中有Python2/3兼容逻辑,要确保在编译时通过宏定义区分(比如#ifdef PY_MAJOR_VERSION)
  • 构建完成后,可以通过python2 -c "import PyHdbscan"和python3 -c "import PyHdbscan"验证是否正常加载

内容的提问来源于stack exchange,提问作者Onalenna Junior Makhura

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:19:37