Подтвердить что ты не робот

Список экспортированных функций из dll с ctypes

Есть ли способ узнать, какие функции экспортируются из dll через библиотеку внешних функций python ctypes?

И если возможно узнать подробности об экспортируемых функциях через c types.

Если да, может ли кто-нибудь предоставить фрагмент кода?

4b9b3361

Ответ 1

Я не думаю, что ctypes предлагает эту функцию. В Windows с визуальной студией:

DUMPBIN -EXPORTS XXX.DLL

Или для включения в окна:

objdump -p XXX.dll

Ответ 2

Если вы находитесь в Linux, есть удобная утилита nm, чтобы перечислить содержимое разделяемой библиотеки (в Linux всегда есть удобная утилита, особенно для C файлов).

Вот вопрос о нем.

Вы используете его с флагом -D: nm -D ./libMyLib.so

Ответ 3

В общем, это невозможно, потому что, как правило, динамически загружаемые библиотеки не несут требуемую метаинформацию. Возможно, эта информация может быть получена в определенных особых случаях с помощью системных способов, но сама ctypes не получает эту информацию. Вы можете записать эту информацию через ctypes (см., Например, restype и argtypes атрибуты указателей функций), но только после того, получил его различными способами.

Ответ 4

@Mark answer использует инструменты Visual Studio.

На окнах вы также можете использовать Dependency Walker, чтобы получить имена функций экспорта DLL.

Иногда имена искажены и не могут использоваться в качестве допустимого имени функции Python.

Вы можете использовать getattr чтобы получить getattr на искаженные функции, например:

mylib = ctypes.cdll('mylib.dll')
my_func = getattr(mylib, '[email protected]')

my_func()

Ответ 5

Если у вас также есть источник для указанной библиотеки, и вы ищете полностью автоматизированный полностью Python способ, вы можете использовать pycparser

для файла: prog.c

typedef short int ret_t;
typedef short int param_t;

ret_t add(param_t a, param_t b) {
    return (ret_t)(a + b);
}

ret_t passthrough(ret_t (* func)(param_t a, param_t b), param_t a, param_t b) {
    // parameter intentionally altered.
    // if this isn't done, compiler will deem entire function redundant
    return func(a, b + 1);
}

компиляция с gcc

gcc -I. -E ./prog.c > prog-preproc.c

дает нам предварительно обработанный файл c: prog-preproc.c затем в питоне:

import pycparser
parser = pycparser.c_parser.CParser()

with open('prog-preproc.c', 'r') as fh:
    ast = parser.parse(fh.read())

class FunctionVisitor(pycparser.c_ast.NodeVisitor):
    def visit_FuncDef(self, node):
        print("found function: %s" % node.decl.name)
        #node.show()

FunctionVisitor().visit(ast)

дает

found function: add
found function: passthrough

Чтобы копать дальше, вы также можете получить параметры и возвращаемые типы. Раскомментируйте node.show() для получения дополнительной информации из дерева абстрактного синтаксиса (AST)

Ответ 6

Приведенный ниже подход работал как для Windows, так и для Ubuntu. Для Windows требуется Cygwin.

Предположим, есть файл c, как показано ниже, имя которого - test.c.

int func1(int a, int b){
    return a + b;
}

int func2(int a, int b){
    return a - b;
}

И приведенные выше коды c были скомпилированы в файл test.dll с помощью следующих команд:

gcc -shared -Wl,-soname,adder -o test.dll -fPIC test.c

А приведенный ниже скрипт Python определяет, какие функции из test.dll могут использоваться Python.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from subprocess import Popen, PIPE

out = Popen(
    args="nm ./test.dll", 
    shell=True, 
    stdout=PIPE
).communicate()[0].decode("utf-8")

attrs = [
    i.split(" ")[-1].replace("\r", "") 
    for i in out.split("\n") if " T " in i
]

from ctypes import CDLL

functions = [i for i in attrs if hasattr(CDLL("./test.dll"), i)]

print(functions)

Вывод, полученный в Windows, выглядит следующим образом:

['func1', 'func2']

Вывод, который я получил в Ubuntu, следующий:

['_fini', 'func1', 'func2', '_init']

Элементы приведенного выше списка являются объектами класса _FuncPtr.

Ответ 7

ДА! есть очень умный нативный способ сделать это.

допустим, вы используете Python ctypes. поместите что-то вроде этого в ваш код C:

1) в вашем коде C:

#define PYEXPORT extern "C" __declspec(dllexport)

Теперь поместите PYEXPORT над функцией, которую вы хотите экспортировать:

PYEXPORT
int myfunc(params){

2) После компиляции вернитесь в Python, откройте ваш файл .c и проанализируйте его следующим образом:

source1_ = open(cfile_name + '.c')
source1 = source1_.read()
source1_.close()
fn = source1.split('PYEXPORT')[-1].split('(')[0].split(' ')[1]

ввод оболочки: fn

вывод оболочки: 'myfunc'

3) Теперь вот умная часть: определите новую функцию в строке:

a1 = """
global get_c_fn
def get_c_fn(dll):
     func = dll."""
a2 = """
return func"""
a3 = a1 + fn + a2

print(a3)
global get_c_fn
def get_c_fn(dll):
    func = dll.myfunc
    return func

СЕЙЧАС выполните exec (a3), и она превратит эту строку в функцию, которую вы можете использовать.

4) сделать обычное:

mydll = ctypes.CDLL(cfile_name + '.dll')
c_fn = get_cuda_fn(mydll)
c_fn.argtypes =  func_params (an array of C-converted inputs you need)
c_fn( *[params] )

и там у вас есть оболочка Python для сценария C без необходимости изменять десять разных вещей каждый раз, когда что-то меняется.

Ответ 8

Внутренне ctypes использует функции, предоставляемые библиотекой динамических ссылок (dlopen/dlsym для unix, LoadLibrary/GetProcAddress для Windows) для загрузки библиотеки и поиска адреса функции, указанной именем функции; а затем используйте библиотеку cffi для динамического прохождения параметра.

Проблема в том, что динамическая библиотека ссылок, в которой ctypes зависит, не включает функцию для отображения символа из общей библиотеки, поэтому вы не можете перечислить символ ctypes.

Для этого вам нужно использовать специальные инструменты для удаления файла эльфа (readelf on unix) и файла pe для dll (dumpbin на windows).