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

如何通过Boost Python与CMake实现条件式合并Python模块至单一库

如何用Boost.Python + CMake构建单库多模块的条件式Python扩展

我刚好折腾过类似的需求,完全可以把原来分散的多个.so合并成一个统一的MyLib.so,同时根据CMake编译选项决定哪些模块会被包含进去。下面分步骤给你拆解实现方法:

第一步:CMake配置——条件式添加源文件

首先要在CMake里定义开关选项,控制是否编译B、C模块的代码,然后把需要的源文件统一打包到MyLib库中:

cmake_minimum_required(VERSION 3.14)
project(MyLib)

# 找到Boost.Python和Python开发依赖
find_package(Boost REQUIRED COMPONENTS python3)
find_package(Python3 REQUIRED COMPONENTS Development)

# 定义编译开关,默认关闭B、C模块
option(BUILD_MODULE_B "把B模块打包进MyLib" OFF)
option(BUILD_MODULE_C "把C模块打包进MyLib" OFF)

# 主库的核心源文件——A模块始终编译
set(MYLIB_SOURCES
    src/A.cpp
)

# 根据开关添加B、C的源文件
if(BUILD_MODULE_B)
    list(APPEND MYLIB_SOURCES src/B.cpp)
endif()
if(BUILD_MODULE_C)
    list(APPEND MYLIB_SOURCES src/C.cpp)
endif()

# 构建Python扩展库,注意要设为SHARED,并且去掉默认的lib前缀
add_library(MyLib SHARED ${MYLIB_SOURCES})

# 链接Boost和Python依赖
target_link_libraries(MyLib
    PRIVATE
        Boost::python3
        Python3::Python
)

# 让生成的库直接叫MyLib.so,而不是libMyLib.so
set_target_properties(MyLib PROPERTIES PREFIX "")

第二步:C++代码结构——向同一个模块注册内容

核心技巧是用BOOST_PYTHON_MODULE_INIT宏,让每个模块的代码都向同一个MyLib命名空间注册内容,而不是各自创建独立模块:

1. 主模块初始化(比如放在A.cpp里)

这是整个MyLib的入口,负责创建模块本身,同时注册A的内容:

#include <boost/python.hpp>
#include "A.h"

namespace bp = boost::python;

// Boost.Python的模块入口函数,创建MyLib模块
BOOST_PYTHON_MODULE(MyLib) {
    bp::object module = bp::scope();
    
    // 注册A类到MyLib模块下
    bp::class_<A>("A")
        .def("some_method", &A::some_method);
    
    // 给模块加个文档说明(可选)
    module.attr("__doc__") = "统一的MyLib模块,包含条件编译的子模块";
}

2. B模块的代码(B.cpp,仅当BUILD_MODULE_B开启时编译)

用BOOST_PYTHON_MODULE_INIT获取已创建的MyLib模块,然后注册B的内容:

#include <boost/python.hpp>
#include "B.h"

namespace bp = boost::python;

// 模块初始化时追加注册B的内容
BOOST_PYTHON_MODULE_INIT(MyLib) {
    bp::object module = bp::scope();
    
    // 把B类注册到MyLib模块下
    bp::class_<B>("B")
        .def("another_method", &B::another_method);
}

3. C模块的代码(C.cpp,仅当BUILD_MODULE_C开启时编译)

和B模块完全同理:

#include <boost/python.hpp>
#include "C.h"

namespace bp = boost::python;

BOOST_PYTHON_MODULE_INIT(MyLib) {
    bp::object module = bp::scope();
    
    bp::class_<C>("C")
        .def("third_method", &C::third_method);
}

第三步:验证效果

编译时根据需要加开关就行:

  • 只编译A模块:cmake .. && make
  • 编译A+B:cmake .. -DBUILD_MODULE_B=ON && make
  • 编译A+B+C:cmake .. -DBUILD_MODULE_B=ON -DBUILD_MODULE_C=ON && make

然后在Python里测试:

import MyLib

# A始终可用
a = MyLib.A()
a.some_method()

# B仅当编译时开启才存在
try:
    b = MyLib.B()
    b.another_method()
except AttributeError:
    print("B模块未启用")

# C仅当编译时开启才存在
try:
    c = MyLib.C()
    c.third_method()
except AttributeError:
    print("C模块未启用")

几个注意点

  • 所有源文件里的BOOST_PYTHON_MODULE_INIT必须用同一个模块名MyLib,不然会注册到不同模块里。
  • 如果你要注册模块级的函数(不是类成员),可以用module.attr("my_func") = bp::make_function(&my_func)的方式添加到MyLib下。
  • 确保CMake找到的Boost.Python版本和你用的Python版本匹配,避免兼容性问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:22:26