簡體   English   中英

Python 擴展多模塊

[英]Python extension with multiple modules

我正在為我編寫的獨立 C 庫構建 Python 綁定。 該庫的文件布局如下:

<project root>
|
`- cpython
|  |
|  `- module1_mod.c
|  `- module2_mod.c
|  `- module3_mod.c
|
`- include
|  |
|  `- module1.h
|  `- module2.h
|  `- module3.h
|
`- src
|  |
|  `- module1.c
|  `- module2.c
|  `- module3.c
|
`- setup.py

我想獲得一個 Python package 以便我可以在my_package.module1my_package.module2等命名空間中導入模塊。

到目前為止,這是我的setup.py

from os import path
from setuptools import Extension, setup


ROOT_DIR = path.dirname(path.realpath(__file__))
MOD_DIR = path.join(ROOT_DIR, 'cpython')
SRC_DIR = path.join(ROOT_DIR, 'src')
INCL_DIR = path.join(ROOT_DIR, 'include')
EXT_DIR = path.join(ROOT_DIR, 'ext')

ext_libs = [
    path.join(EXT_DIR, 'ext_lib1', 'lib.c'),
    # [...]
]

setup(
    name="my_package",
    version="1.0a1",
    ext_modules=[
        Extension(
            "my_package.module1",
            [
                path.join(SRC_DIR, 'module1.c',
                path.join(MOD_DIR, 'module1_mod.c',
            ] + ext_libs,
            include_dirs=[INCL_DIR],
            libraries=['uuid', 'pthread'],
        ),
    ],
)

導入mypackage.module1有效,但問題是module2module3也需要外部庫(並非所有模塊都需要外部庫),我假設如果我在其他模塊中包含相同的外部庫,我會得到很多膨脹。

我查看了 Github 中的示例設置,但沒有找到解決此問題的示例。

什么是組織我的構建的好方法?

編輯:這實際上是一個更嚴重的問題,因為我在module1中有module2 module2的 object 需要在 module1 中定義的module1類型。 如果我創建單獨的二進制文件而不包括每個依賴項的所有源,則符號在鏈接時將不可用,從而增加了跟蹤哪個模塊所需內容的冗余和復雜性。

在深入研究 Python 錯誤報告和幾乎沒有文檔記錄的功能后,我找到了一個答案,它解決了多個外部依賴項和內部交叉鏈接。

解決方案是創建一個整體“模塊”,其中定義了所有模塊,然后在 package 初始化文件中使用幾行 Python 代碼公開它們。

為此,我將模塊源文件更改為 header 文件,維護他們的大部分方法 static 並且只公開PyTypeObject結構和我的 object 類型的結構,因此它們可以用於其他模塊。

然后我移動了PyMODINIT_FUNC函數,它定義了“包”模塊( py_mypackage.c )中的所有模塊,該模塊還定義了一個空模塊。 “包”模塊定義為_my_package

最后,我在__init__.py腳本中添加了一些內部機制,該腳本從.so 文件中提取模塊符號並將它們公開為 package 的模塊。 這記錄在Python 文檔中:

import importlib.util
import sys

import _my_package


pkg_path = _my_package.__file__


def _load_module(mod_name, path):
    spec = importlib.util.spec_from_file_location(mod_name, path)
    module = importlib.util.module_from_spec(spec)
    sys.modules[mod_name] = module
    spec.loader.exec_module(module)

    return module


for mod_name in ('module1', 'module2', 'module3'):
    locals()[mod_name] = _load_module(mod_name, pkg_path)

因此,新的布局是:

<project root>
|
`- cpython
|  |
|  `- my_package
|    |
|    `- __init__.py
|
|  `- py_module1.h
|  `- py_module2.h
|  `- py_module3.h
|  `- py_mypackage.c
|
`- include
|  |
|  `- module1.h
|  `- module2.h
|  `- module3.h
|
`- src
|  |
|  `- module1.c
|  `- module2.c
|  `- module3.c
|
`- setup.py

setup.py

setup(
    name="my_package",
    version="1.0a1",
    package_dir={'my_package': path.join(CPYTHON_DIR, 'my_package')},
    packages=['my_package'],
    ext_modules=[
        Extension(
            "_my_package",
            "<all .c files in cpython folder + ext library sources>",
            libraries=[...],
        ),
    ],
)

出於好奇,完整的代碼位於https://notabug.org/scossu/lsup_rdf/src/e08da1a83647454e98fdb72f7174ee99f9b8297c/cpython (固定在當前提交處)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM