liste des fonctions exportées de dll avec ctypes
y a-t-il un moyen de savoir quelles fonctions sont exportées de la dll
par la bibliothèque de fonctions étrangères python ctypes
?
et si possible de connaître les détails sur les fonctions exportées à travers c types
.
dans l'affirmative, quelqu'un pourrait-il fournir un extrait de code?
7 réponses
Je ne pense pas que les ctypes offrent cette fonctionnalité. Sous Windows avec visual studio:
DUMPBIN -EXPORTS XXX.DLL
ou pour mingw sur windows:
objdump -p XXX.dll
si vous êtes sous Linux, il y a un utilitaire pratique nm
pour lister le contenu d'une bibliothèque partagée (il y a toujours un utilitaire pratique sous Linux, surtout pour les choses en C.)
vous l'utilisez avec le drapeau -D
: nm -D ./libMyLib.so
en général, ce n'est pas possible, parce que, encore une fois en général, les bibliothèques chargées dynamiquement ne contiennent pas les méta-informations dont vous avez besoin. Il est peut-être possible d'obtenir cette information dans certains cas particuliers par des moyens propres au système, mais ctypes
lui-même ne recueille pas cette information. Vous pouvez enregistrer telles informations via ctypes
(voir par exemple les attributs restype et argtypes
des pointeurs de fonction), mais seulement après vous les avez obtenus par des moyens différents.
@Mark's answer utilise Visual Studio tools.
sous windows, vous pouvez également utiliser Dependency Walker pour obtenir les noms de fonction des exportations dll.
parfois les noms sont déformés et ne peuvent pas être utilisés comme nom de fonction python valide.
vous pouvez utiliser getattr
pour obtenir une poignée à fonctions mutilées, E. g:
mylib = ctypes.cdll('mylib.dll')
my_func = getattr(mylib, '_my_func@0')
my_func()
si vous avez aussi la source de ladite bibliothèque, et que vous êtes à la recherche d'un tout-Python entièrement automatisé, vous pouvez utiliser pycparser
pour le fichier: 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);
}
compilant avec gcc
gcc -I. -E ./prog.c > prog-preproc.c
nous donne le fichier c pré-traité: prog-preproc.c
puis en python:
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)
rendements
found function: add
found function: passthrough
pour creuser plus loin vous pouvez aussi obtenir les types de paramètre et de retour.
Décommenter node.show()
pour plus d'informations à partir de l'intérieur de l'Arbre de Syntaxe Abstraite (AST)
je vais libérer une bibliothèque pour cela bientôt (je vais essayer de me rappeler de revenir et de laisser tomber un lien)
en interne, ctypes utilise des fonctions fournies par la bibliothèque de lien dynamique (dlopen/dlsym sur unix, LoadLibrary / Getrocaddress sur windows) pour charger la bibliothèque et trouver l'adresse de la fonction spécifiée par le nom de la fonction; et puis utiliser la bibliothèque cffi pour passer le paramètre de manière dynamique.
le problème est que la bibliothèque de liens dynamiques dont dépend ctypes n'inclut pas de fonction pour lister le symbole de la bibliothèque partagée, c'est pourquoi vous ne pouvez pas lister le symbole par ctypes.
pour ce faire, vous devez utiliser des outils spécifiques pour Dumper le fichier elf (readelf sur unix) et le fichier pe Pour dll (dumpbin sur windows).
Oui! il y a une méthode autochtone très intelligente pour le faire.
disons que vous utilisez des ctypes Python. mettez quelque chose comme ça dans votre code C:
1) dans votre code C:
#define PYEXPORT extern "C" __declspec(dllexport)
mettez maintenant PYEXPORT au-dessus de la fonction que vous voulez exporter:
PYEXPORT
int myfunc(params){
2) Après la compilation, retournez en Python et ouvrez votre .c fichier, et l'analyse semblable à ceci:
source1_ = open(cfile_name + '.c')
source1 = source1_.read()
source1_.close()
fn = source1.split('PYEXPORT')[-1].split('(')[0].split(' ')[1]
entrée shell: fn
sortie shell: 'myfunc'
3) Maintenant voici la partie intelligente: définir une nouvelle fonction dans une chaîne de caractères:
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
MAINTENANT que exec(a3) et il va transformer cette chaîne en une fonction que vous pouvez utiliser.
4) Faire comme d'habitude:
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] )
et là vous avez un wrapper python pour un script C sans avoir à modifier dix choses différentes chaque fois que quelque chose change.