首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在构建时设置cdll搜索路径?

如何在构建时设置cdll搜索路径?
EN

Stack Overflow用户
提问于 2022-01-09 10:56:09
回答 2查看 289关注 0票数 0

我在一个非标准文件夹中有一个分解库libcustum.so,还有一个使用ctypes.cdll.LoadLibrary("libcustom.so")的python包。

如何在构建时设置libcustum.so路径(类似于rpath)?

代码语言:javascript
运行
复制
env LD_LIBRARY_PATH=/path/to/custum/lib python3 -c "import mypackage"

工作正常,但我不想使用全局LD_LIBRARY_PATH,也不想在运行时设置库路径。

代码语言:javascript
运行
复制
python3 -c "import mypackage"

结果是:

代码语言:javascript
运行
复制
OSError: libcustum.so: cannot open shared object file: No such file or directory
EN

回答 2

Stack Overflow用户

发布于 2022-01-09 22:59:24

我找到的唯一解决方案(必须有更好的解决方案)是创建一个python模块来封装dlopen调用。因此,可以在编译时插入rpath,以便在运行时解析动态链接。

代码语言:javascript
运行
复制
/* _custom.c */
#include <Python.h>
#include <dlfcn.h>

static struct PyModuleDef _custommodule = {
    PyModuleDef_HEAD_INIT,
    .m_name = "_custom",
    .m_doc = "Convenience module, libcustom.so wrapper",
    .m_size = -1
};

PyMODINIT_FUNC
PyInit__custom(void)
{
    PyObject *self = NULL, *ctypes = NULL, *cdll = NULL, *lib = NULL;

    /* We must import the library a first time here to allow the use
       of rpath. Otherwise `ctypes.cdll.LoadLibrary` uses dlopen from
       an internal python module, and the internal module's rpath will
       be used for link resolution instead of our. */
    if (! dlopen("libcustom.so", RTLD_NOW | RTLD_LOCAL)) {
        PyErr_SetString(PyExc_ImportError, dlerror());
        return NULL;
    }
    if (! (self = PyModule_Create(&_custommodule))) goto fail;
    if (! (ctypes = PyImport_ImportModule("ctypes"))) goto fail;
    if (! (cdll = PyDict_GetItemString(PyModule_GetDict(ctypes), (char*) "cdll"))) goto fail;
    if (! (lib = PyObject_CallMethod(cdll, "LoadLibrary", "s", "libcustom.so"))) goto fail;
    if (PyModule_AddObject(self, "_lib", lib) < 0) goto fail;

    Py_DECREF(ctypes);
    Py_DECREF(cdll);
    return self;

 fail:
    PyErr_SetString(PyExc_ImportError, "Internal error");
    Py_XDECREF(self);
    Py_XDECREF(ctypes);
    Py_XDECREF(cdll);
    Py_XDECREF(lib);
    return NULL;
}

然后我们将这个扩展添加到python包中:

代码语言:javascript
运行
复制
# setup.py
setup(
    ext_modules=[Extension("mypackage._custom", ["_custom.c"])],
    ...
)

然后,在构建包时,我们可以插入rpath:

代码语言:javascript
运行
复制
python3 setup.py build_ext --rpath /path/to/custom/lib
python3 setup.py install

它只剩下用ctypes.cdll.LoadLibrary("libcustom.so")代替importlib.import_module("mypackage._custom")._lib

票数 0
EN

Stack Overflow用户

发布于 2022-01-11 16:24:00

清单[Python.Docs]:ctypes用于Python的外部函数库

您可以将完整的.dll名称传递给CDLL (或cdll.LoadLibrary)。

code00.py

代码语言:javascript
运行
复制
#!/usr/bin/env python

import ctypes as ct
import os
import sys
from custom_dll_path import CUSTOM_DLL_PATH


DLL_NAME = "dll00.{:s}".format("dll" if sys.platform[:3].lower() == "win" else "so")


def main(*argv):
    if argv:
        dll_name = DLL_NAME
    else:
        dll_name = os.path.join(CUSTOM_DLL_PATH, DLL_NAME)
    print("Attempting to load: {:s}".format(dll_name))
    dll00 = ct.CDLL(dll_name)


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.")
    sys.exit(rc)

setup.py

代码语言:javascript
运行
复制
#!/usr/bin/env python

import sys
from setuptools import Command, setup


class SetDllPath(Command):
    user_options = [
        ("path=", "p", "Dll path"),
    ]

    def initialize_options(self):
        self.path = ""

    def finalize_options(self):
        pass

    def run(self):
        with open("custom_dll_path.py", "w") as f:
            f.write("CUSTOM_DLL_PATH = \"{:s}\"\n".format(self.path))


setup(
    name="custom_project",
    cmdclass={
        "set_dll_path": SetDllPath,
    },
    #  Other stuff ...
)

输出

cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q070640586> ~/sor.sh ###设置较短的提示符,当粘贴到StackOverflow (或其他)页面时,### 064位prompt> ls代码00.py setup.py 064位prompt> echo "int f() {返回0;}“> dll00.c 064位prompt> gcc -fPIC -shared -o Dev 00.so dll00.c 064 mnt prompt> ls code0.py dll00.c Dev 00.c setup.py 064位prompt> 064位prompt> 064位prompt> python3.9 setup.py set_dll_path -p $(pwd)运行set_dll_path 064位prompt> ls码00.py custom_dll_path.py dll0.c Dev 00.so setup.py 064 mnt prompt> prompt> custom_dll_path.py prompt>= "/mnt/e/Work/Dev/StackOverflow/q070640586”060640586“064bit -p en19 en19#python3.9代码00.py虚拟args失败Python 3.9.9 (main,2021年11月16日,03:08:02) GCC 9.3.0 064位在linux上试图加载: dll00.so回溯(最近一次调用):文件"/mnt/e/Work/Dev/StackOverflow/q070640586/code00.py",行24,在rc = main(*sys.argv1:)文件"/mnt/e/Work/Dev/StackOverflow/q070640586/code00.py",行18,在main dll00 = ct.CDLL(dll_name) File“/usr/lib/python3.9/ctype/_init__..py”,第374行,在__init__ self._handle = _dlopen(self._name,mode) OSError: dll00.so:无法打开共享对象文件:没有这样的文件或目录064位prompt> 064位prompt> 064位prompt> python3.9编码00.py Python 3.9.9 (main,11月16日2021,03:08:02) GCC 9.3.0 064位在linux上尝试加载:完成。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70640586

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档