2016-04-10 21 views
4

Bir C programına bir python programı yerleştirmeye çalışıyorum. İşletim Sistemim Ubuntu 14.04Python'u C'ye Gömme Bağlamada hata - tanımsız başvuru PyString_AsString

Aynı C kod tabanında (ayrı uygulamalar olarak) python 2.7 ve python 3.4 yorumlayıcılarını yerleştirmeye çalışıyorum. Derleme ve bağlantı python 2.7 gömülü çalışır ancak python için 3.4 çalışır. Linker aşamasında başarısız olur. İşte

import sys 

def get_version(): 
    version = '.'.join(str(v) for v in sys.version_info[:3]) 
    print("version: ", version) 
    return version 

kullanıyorum programı derlemek benim C kodu (sadece bir örnek değil gerçek kodu)

simple.c

#include <stdio.h> 
#include <Python.h> 

int main(int argc, char *argv[]) 
{ 
    PyObject *pName, *pModule, *pFunc, *pValue; 
    char module[] = "get_version"; 
    char func[] = "get_version"; 
    char module_path[] = "."; 

    Py_Initialize(); 
    PyObject *sys_path = PySys_GetObject("path"); 
    PyList_Append(sys_path, PyUnicode_FromString(module_path)); 

    pName = PyUnicode_FromString(module); 
    pModule = PyImport_Import(pName); 
    Py_DECREF(pName); 

    if(pModule != NULL) 
    { 
     pFunc = PyObject_GetAttrString(pModule, func); 
     if (pFunc && PyCallable_Check(pFunc)) 
     { 
      pValue = PyObject_CallObject(pFunc, NULL); 
      if (pValue != NULL) { 
       printf("Python version: %s\n", PyString_AsString(pValue)); 
       Py_DECREF(pValue); 
      } 
      else { 
       Py_DECREF(pFunc); 
       Py_DECREF(pModule); 
       PyErr_Print(); 
       fprintf(stderr,"Call failed\n"); 
       return 1; 
      } 
     } 
    } 

    Py_Finalize(); 
    return 0; 
} 

get_version.py olduğunu gcc.

gcc `python-config --cflags` simple.c `python-config --ldflags` 

bayrakları olarak genişletmek:

piton-config --cflags:-I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7 -fno-strict-aliasing -D_FORTIFY_SOURCE=2 -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes

Öncelikle derleme ve ben çalıştırmak derleme 2.7 python ayarlı bayrakları bağlama ve aşağıdaki komutu kullanarak bağlama ile

piton-config LDFLAGS:-L/usr/lib/python2.7/config-x86_64-linux-gnu -L/usr/lib -lpthread -ldl -lutil -lm -lpython2.7 -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions

Sorun olmadan sorunsuz çalışıyor. Ben python3.4 bayraklarıyla aynı derlemeye çalıştığınızda başarısız:

gcc `python3-config --cflags` simple.c `python3-config --ldflags` 

bayrakları olarak genişletmek:

piton-config --cflags:-I/usr/include/python3.4m -I/usr/include/python3.4m -Wno-unused-result -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes

piton -config - lflalags:-L/usr/lib/python3.4/config-3.4m-x86_64-linux-gnu -L/usr/lib -lpython3.4m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions

Hata mesajı:

simple.c: In function ‘main’: 
simple.c:27:17: warning: implicit declaration of function ‘PyString_AsString’ [-Wimplicit-function-declaration] 
       printf("Python version: %s\n", PyString_AsString(pValue)); 
       ^
simple.c:27:17: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=] 
/tmp/ccaoMdTo.o: In function `main': 
/home/vagrant/c_python_api/simple.c:27: undefined reference to `PyString_AsString' 
collect2: error: ld returned 1 exit status 

nesneler belirtilen linkeri sırasını değiştirerek çalıştı. Ama şans yok. Bunun neden böyle olacağı hakkında bir fikrin var mı?

Yardımlarınız için teşekkürler!

cevap

3

Python 3 does not have PyString_AsString any more; Python 3 str, Python 2 unicode nesnelerine karşılık gelir; Python 3'te str işlemek için kullanılan işlevlerin adları, C-API'sinde PyUnicode_ olarak belirtilmiştir.

Böylece bu satırı:

printf("Python version: %s\n", PyString_AsString(pValue)); 

Python 3 PyUnicode_AsUTF8 kullanmak değiştirilebilir:

#if PY_MAJOR_VERSION >= 3 
printf("Python version: %s\n", PyUnicode_AsUTF8(pValue)); 
#else 
printf("Python version: %s\n", PyString_AsString(pValue)); 
#endif 

(Değil

yani tanımsız davranış olacaktır printf %s için NULL geçtiğinin bir nedenle 'NULL olmayan bir işaretçinin döndüğünü kontrol etmek istiyorum')

+0

Hızlı yanıt için teşekkür ederiz. Sizin tarafınızdan sağlanan çözüm işe yaradı. Python3 dizelerinin varsayılan olarak kodlanmış unicode olduğunu biliyordum, bunun hakkında bir düşünceye sahip olmalıydı. Ancak, çözümünüzde belirtildiği gibi UTF8String PyObject'dir ve yerel karakterlere dönüştürülemez. Burada açıklandığı gibi (http://stackoverflow.com/a/16905726/4104863) PyBytes_AsString() işlevine ek işlev çağrısı yapılmalıdır. Bunu içerecek şekilde cevabı düzenleyeceğim. –

+0

Ah özür dilerim: D Cevap yazıyordu: Sabit –

+0

@JahanBalasubramaniam 'PyUnicode_AsUTF8' olmalıydı; Bu, str'nin kendisi olduğu sürece geçerli olan UTF-8 olarak kodlanmış dizeye paylaşılan bir işaretçi döndürür. –