2015-05-26 2 views
3

извините за еще один вопрос о dynamic module does not define init function. Я перешел к более старым вопросам, но я не нашел тот, который достаточно подробно остановил мой случай.numpy ctypes «динамический модуль не определяет функцию функции init», если не перекомпилирован каждый раз

У меня есть библиотека C++, которая должна экспортировать несколько функций в python (например, ~ 5 функций, определенных в блоке extern "C" {}). Он отлично работает, когда я перекомпилирую библиотеку каждый раз, когда я ее импортирую. Тем не менее, если я импортировать его без повторной компиляции он дает ошибку ImportError: dynamic module does not define init function (initmylib)

Очень упрощенный пример, который воспроизводят такое же поведение (ошибка) выглядит следующим образом:

C++ библиотеки кода в файле mylib.cpp

#include <math.h> 
// there are some internal C++ functions and classes 
// which are not exported, but used in exported functions 
extern "C"{ 
// one of the functions which should be accessible from python 
void oscilator(double dt, int n, double * abuff, double * bbuff){ 
    double a = abuff[0]; 
    double b = bbuff[0]; 
    for (int i=1; i<n; i++){ 
     a = a - b*dt; 
     b = b + a*dt; 
     abuff[i] = a; 
     bbuff[i] = b; 
    } 
} 
// there are also other functions but let's keep this example simple 
// int initmylib(){ return 0; } // some junk ... if this makes ctypes happy ? 
} 

питона сновальщик mylib.py из C++ библиотеки mylib.cpp:

import numpy as np 
from ctypes import c_int, c_double 
import ctypes 
import os 

name='mylib' 
ext='.so' # if compited on linux .so on windows .dll 

def recompile( 
     LFLAGS="", 
     #FFLAGS="-Og -g -Wall" 
     FFLAGS="-std=c++11 -O3 -ffast-math -ftree-vectorize" 
    ): 
    import os 
    print " ===== COMPILATION OF : "+name+".cpp" 
    print os.getcwd() 
    os.system("g++ "+FFLAGS+" -c -fPIC "+name+".cpp -o "+name+".o"+LFLAGS) 
    os.system("g++ "+FFLAGS+" -shared -Wl,-soname,"+name+ext+" -o "+name+ext+" "+name+".o"+LFLAGS) 

# this will recompile the library if somebody delete it 
if not os.path.exists("./"+name+ext): 
    recompile() 

lib = ctypes.CDLL("./"+name+ext) 

array1d = np.ctypeslib.ndpointer(dtype=np.double, ndim=1, flags='CONTIGUOUS') 

# void oscilator(double dt, int n, double * abuff, double * bbuff) 
lib.oscilator.argtypes = [ c_double, c_int, array1d, array1d ] 
lib.oscilator.restype = None 
def oscilator(dt, a, b): 
    n = len(a) 
    lib.oscilator(dt, n, a, b) 

питон про грамм test.py, который импортирует mylib

import os 
from pylab import * 
from basUtils import * 

# this will delete all compiled files of the library to force recompilation 
def makeclean(): 
    [ os.remove(f) for f in os.listdir(".") if f.endswith(".so") ] 
    [ os.remove(f) for f in os.listdir(".") if f.endswith(".o") ] 
    [ os.remove(f) for f in os.listdir(".") if f.endswith(".pyc") ] 

# if I do makeclean() every time it works, if I do not it does not 
#makeclean() 

import mylib 

a=zeros(100) 
b=zeros(100) 
a[0] = 1 

mylib.oscilator(0.1, a, b) 

plot(a) 
plot(b) 

show() 

Я также пытался сделать ctypes счастливым, добавив некоторые int initmylib(){ return 0; } функцию в mylib.cpp, как вы можете видеть в коде выше. однако это приведет к ошибке SystemError: dynamic module not initialized properly

У меня нет этой проблемы, когда я компилирую пример cos_doubles из заметок лекции. Однако этот пример работает только в том случае, если я хочу импортировать только одну функцию с тем же именем, что и имя библиотеки. Я хочу нечто более общее.

+0

eryksun> ах, спасибо, вы правы, имя файла скомпилированной библиотеки является проблемой. С 'lib_mylib.so' отлично работает. Вы хотите, чтобы regyer ответ, чтобы я мог принять его и закрыть вопрос? –

ответ

1

Попробуйте запустить import imp; print imp.find_module('mylib')[1]. Вы удивлены, что он выбирает mylib.so вместо mylib.py? Интерпретатор ожидает, что mylib.so будет модулем расширения, который для CPython 2.x должен определить функцию инициализации с именем initmylib. Чтобы избежать случайной попытки импортировать общую библиотеку, либо смените имя на что-то вроде _mylib.so или mylib.1.0.so, либо просто сохраните файл в каталоге, который находится не в sys.path.

Обратите внимание, что модули расширения Windows - это библиотеки DLL, но с расширением .pyd вместо .dll. Таким образом, import mylib не будет пытаться загрузить mylib.dll.

+0

eryksun> ах, спасибо, вы правы, имя файла скомпилированной библиотеки - проблема. С lib_mylib.so отлично работает. –