代码之家  ›  专栏  ›  技术社区  ›  A. Reed

Python C扩展子模块错误:没有名为“x”的模块

  •  1
  • A. Reed  · 技术社区  · 6 年前

    我很难在代码中将C扩展作为子模块。下面的C扩展编译得很好。当我尝试将其添加到另一个模块时,就会出现问题。

    这是C代码:文件名是prctl3-0。c、 我能够为两个Python2编译它。7和Python 3.0。

    #include <Python.h>
    
    #include <stdio.h>
    #include <string.h>
    #include <sys/prctl.h>
    
    // Now we need to identify which version of Python we are working with.
    //  For backwards compatibility, we need to be able to be compiled by either
    //  Python 2.7 or Python3.x.
    
    #if PY_MAJOR_VERSION >=3
    #define PY_3CODE            // We will use this pre-compile statement to differentiate
                                //  between code for Py2.7 and 3.x
    #endif
    
    /* osCall_changeName
      Calls prctl() to change the name of the calling thread, process or subprocess
    
    */
    static PyObject* osCall_changeName(PyObject*self, PyObject* args)
    {
      const char *passedInName;   // Name passed in by the system
      size_t nameLength;          // Calculated by calling strlen() on passedInName
    
      char newName[16];           // In Python newName= passedInName[0:15]+ \0
      int nameChangeRes;          // stores error code for calling prctl()
    
      PyObject *retName;          // Return value; Python None if error occurs
    
      // Check if argument passed in successfully
      if(! PyArg_ParseTuple(args, "s", &passedInName)){
        printf("Error in arg passing\n");
        Py_RETURN_NONE;
      }
    
      nameLength = strlen(passedInName);
      if( nameLength > 15){       // prctl() automatically truncates, but unsure if new string is null-terminated
         strncpy(newName, passedInName, 15);
         newName[15] = '\0';
      } else {
        strcpy(newName, passedInName);
      }
    
      //Actual function call
      nameChangeRes = prctl(PR_SET_NAME, newName, 0,0,0);
    
      if( nameChangeRes == 0 )    // Success; pass back the changed name value
      {
        retName = Py_BuildValue("s", newName);
        return retName;
      }
    
      // Method failed; return None
      Py_RETURN_NONE;
    }
    
    static PyObject* osCall_getName(PyObject* self) {
    
      char procName[16];          // Buffer to put prctl results into
      int  nameRetrieveRes;       // Result of the name retrieval operation
      PyObject *retName;          // Python object to return values
    
    
      nameRetrieveRes = prctl(PR_GET_NAME, procName, 0,0,0);
    
      if ( nameRetrieveRes == 0 ) //
      {
          retName = Py_BuildValue("s", procName);
          return retName;
      }
      printf("Process name change failed\n");
      // Operation failed; return None
      Py_RETURN_NONE;
    }
    
    //==========================================================
    //  STEP 2: COMPILE THE PIECES NEEDED FOR EITHER 2.7 OR 3.X
    //    PYTHON LIBRARIES
    //==========================================================
    
    static PyMethodDef proc_OsFunc[] = {
      { "changeName",
      (PyCFunction)osCall_changeName,
      METH_VARARGS,
      "Function to give Python process a new associated string ID"},
    
      { "getName",
      (PyCFunction)osCall_getName,
      METH_NOARGS,
      "Function to get Python process's current string ID"
      },
    
      {NULL, NULL, 0, NULL} //function array terminator
    };
    
    #ifdef PY_3CODE
    static struct PyModuleDef osCallDefine = {
      PyModuleDef_HEAD_INIT,
      "prctl3_0",
      "A simple library for accessing prctl() on Linux from Python 3.0",
      -1,
      proc_OsFunc
    };
    
    #endif
    
    #ifdef PY_3CODE
    // Python 3.0 initialization syntax
    PyMODINIT_FUNC PyInit_prctl3_0(void)
    {
      Py_Initialize();
    
      return PyModule_Create(&osCallDefine);
    }
    
    #else
    // Python 2.0 initialization syntax
    PyMODINIT_FUNC initprctl3_0() {
      Py_InitModule3("prctl3_0",proc_OsFunc,
            "A simple library for accessing prctl() on Linux from Python 2.0");
    }
    
    
    
    #endif
    

    我希望在模块名称中包含此代码 mpIPC 作为更大项目的一部分。我遇到的问题是,当我将其放入一个更大的模块中,并尝试使用以下代码访问它时,我得到以下结果:

    >>> import mpIPC.prctl3_0
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ImportError: No module named prctl3_0
    

    我的 setup.py 文件如下:

    from setuptools import setup, find_packages, Extension
    
    prctl_module = Extension("mpIPC.prctl3_0",
                                    sources = ["mpIPC/prctl3_0.c"])
    
    setup(name = "mpIPC",
        version = '0.0',
        description = "Python C module for accessing Linux commands for IPC",
        packages = ['mpIPC'],
        ext_modules = [prctl_module] )
    

    此模块的我的文件目录:

    project/
    +- setup.py
    +- mkdir/
    -+- __init__.py 
    -+- prctl3_0.c
    -+- os.py   # used for other Linux os calls
    

    我不确定我错过了什么。我还检查了以下链接: How to build a Python C Extension so I can import it from a module 但在这一点上,它并没有真正帮助我。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Oliver Baumann    6 年前

    我让它在没有任何源代码修改的情况下工作。

    1. 您的目录“mkdir” 必须 命名为“mpIPC”,这是模块名称。您希望目录结构看起来像底部

    2. 尝试从源目录中进行测试,即不要从 project ,因为根据Python的模块结构,它将尝试从目录“mpIPC”(您将在1中创建)导入(此提示的来源是 this comment in the post you mentioned 。例如,可以在您的home dir中的任何位置进行尝试。也就是说,假设你跑了 python setup.py install 第一个:)

    目录树:

    foobar
        ├── mpIPC
        │   ├── __init__.py
        │   ├── os.py
        │   └── prctl3_0.c
        └── setup.py