如果不每次重新编译,使用numpy ctypes时会出现"dynamic module does not define init function"错误。

7
抱歉再次提问关于“dynamic module does not define init function”的问题。我浏览了旧的问题,但没有找到一个特别符合我的情况的答案。
我有一个C++库,应该向Python导出几个函数(例如,在extern "C" {}块中定义的5个函数)。每次重新编译库并导入时,它都能正常工作。但是,如果我不重新编译就导入它,它会出现错误ImportError: dynamic module does not define init function (initmylib) 下面是一个简化的示例,重现了相同的行为(错误):
文件mylib.cpp中的C++库代码。
#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 ?
}

Python包装器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 )

Python程序 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()

我还试图通过在mylib.cpp中添加一些函数int initmylib( ){ return 0; }来让ctypes满意,如上面的代码所示。然而,这会产生错误SystemError: dynamic module not initialized properly
当我编译scipy讲义中cos_doubles的示例时,我没有遇到这个问题。但是,这个示例只适用于想要导入与库名称相同的一个函数的情况。我想要更通用的东西。

eryksun > 啊,谢谢,你说得对,编译库的文件名是问题所在。使用 lib_mylib.so 就可以正常工作了。你想给出一个正式的答案,这样我就可以接受并关闭这个问题吗? - Prokop Hapala
1个回答

7
尝试运行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。

eryksun > 啊,谢谢,你说得对,编译库的文件名是问题所在。使用 lib_mylib.so 就可以正常工作了。 - Prokop Hapala

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接