当前位置:   article > 正文

python distutils打包C/C++模块,执行python setup.py build_ext --inplace时报错cl

python setup.py build_ext --inplace

一、问题发生环境

python可以把C/C++代码编译并打包为pyd模块,从而可以使python脚本直接调用C/C++模块功能。

我在执行python setup.py build_ext --inplace时遇到了缺失cl.exe的错误提示,然后用pip安装了cl。

再次编译,提示cl: error: no such option: -I,改变cl版本仍然不行,百思不得其解。

二、解决办法

后来意识到C/C++模块的编译实际上还是python调用专门的C/C++编译器进行编译的,在另一台电脑上全新的环境上运行,发现系统默认执行的是Microsoft Visual C++ (14.0以上版本)下的cl来编译C/C++,而不是python下的cl。

Microsoft C++ 生成工具 - Visual Studio

下Microsoft生成工具,具体安装方法可以搜索“解决报错 Microsoft Visual C++ 14.0 is required”,网上有很多相关文档。

之后就可以正常调用MSVC的cl来编译打包pyd啦。

三、python distutils使用方法

下面记录一下python distutils的使用方法。

  1. 创建一个test文件夹。

  1. 编辑一个test.c,随便写个Hello world就麻烦:

  1. include <Python.h>,以PyMODINIT_FUNC为标志写一个Python Module init函数来Create一个Python Module “test”。

其中,PyObject、PyModule_Create等都定义在Python.h中,并且Python.h已经include了stdio.h。

  1. PyMODINIT_FUNC PyInit_test(void)
  2. {
  3. PyObject *m;
  4. m = PyModule_Create(&test);
  5. if (m == NULL)
  6. {
  7. return Py_BuildValue("");
  8. }
  9. return m;
  10. }
  1. 定义Python Module “test”,test_methods指向test module的方法。

  1. PyMethodDef test_methods[] =
  2. {
  3. {"hello", hello, METH_VARARGS, "print a hello world"},
  4. {NULL, NULL, 0, NULL}
  5. };
  6. struct PyModuleDef test =
  7. {
  8. PyModuleDef_HEAD_INIT,
  9. "test", // name of module /
  10. NULL, // module documentation, may be NULL /
  11. -1, // size of per-interpreter state of the module, or -1 if the module keeps state in global variables. /
  12. test_methods // A pointer to a table of module-level functions, described by PyMethodDef values. Can be NULL if no functions are present. /
  13. };
  1. 终于可以写Hello World了,注意返回值类型应为PyObject*,直接把全部代码放上来吧。

  1. #include <Python.h>
  2. PyObject* hello()
  3. {
  4. printf("Hello World!");
  5. return Py_True;
  6. }
  7. PyMethodDef test_methods[] =
  8. {
  9. {"hello", hello, METH_VARARGS, "print a hello world"},
  10. {NULL, NULL, 0, NULL}
  11. };
  12. struct PyModuleDef test =
  13. {
  14. PyModuleDef_HEAD_INIT,
  15. "test", // name of module /
  16. NULL, // module documentation, may be NULL /
  17. -1, // size of per-interpreter state of the module, or -1 if the module keeps state in global variables. /
  18. test_methods // A pointer to a table of module-level functions, described by PyMethodDef values. Can be NULL if no functions are present. /
  19. };
  20. PyMODINIT_FUNC PyInit_test(void)
  21. {
  22. PyObject *m;
  23. m = PyModule_Create(&test);
  24. if (m == NULL)
  25. {
  26. return Py_BuildValue("");
  27. }
  28. return m;
  29. }

  1. 在test目录下创建一个setup.py,编辑如下:

  1. from distutils.core import setup, Extension
  2. module1 = Extension('test',
  3. sources = ['test.c'])
  4. setup (name = 'test',
  5. version = '1.0',
  6. description = 'test extention',
  7. ext_modules = [module1])

name、version等都不必要,只有ext_modules必要。

  1. 执行python setup.py build_ext --inplace,生成test.cp38-win_amd64.pyd,pyd就是python dll,可以直接被python脚本调用的。

  1. 最后写个python脚本test.py调用一下test模块测试一下:

  1. import test
  2. test.hello()

输出Hello World!,完美。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/46981
推荐阅读
相关标签
  

闽ICP备14008679号