你如何使用命令行驱动的应用程序中的python3 C API? [英] How do you use the python3 c api for a command line driven app?

查看:443
本文介绍了你如何使用命令行驱动的应用程序中的python3 C API?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在使用一个自定义的,现在建立作为virtualenv中一会儿一个替代品,它的高明。它需要更长的时间来构建的,但它的实际工作,而且也从未螺丝了。

I've been using a custom build as a replacement for virtualenv for a while now, and it's brillant. It takes longer to build, but it actually works, and it never screws up.

这在一个简单的Python包装,增加了一些特定的文件夹到库路径,我发现非常有用的部分。在code,因为这是微不足道的:

Part of this in a simple python wrapper that adds some specific folders to the library path, which I've found very useful. The code for it is trivial:

#include <stdio.h>
#include <n/text/StringUtils.h>
#include <Python.h>

int main(int argc, char *argv[]) {

  /* Setup */
  Py_SetProgramName(argv[0]);
  Py_Initialize();
  PySys_SetArgv(argc, argv);

  /* Add local path */
  PyObject *sys = PyImport_ImportModule("sys");
  PyObject *path = PyObject_GetAttrString(sys, "path");

  /* Custom path */
  char *cwd = nrealpath(argv[0]);
  char *libdir = nstrpath(cwd, "python_lib", NULL);
  PyList_Append(path, PyString_FromString(libdir));
  free(cwd);
  free(libdir);

  /* Run the 'main' module */
  int rtn = Py_Main(argc, argv); // <-- Notice the command line arguments.
  Py_Finalize();

  return rtn;
}

所以,移动到python3是好的吧?所以......

So, moving to python3 is good right? So...

我尽职尽责地更换调用PyString_FromString()与PyByte_FromString(),并试图重新编译,但它引发的错误:

I dutifully replaced the call to PyString_FromString() with PyByte_FromString() and tried to recompile, but it raises errors:

/Users/doug/env/src/main.c:8:21: error: incompatible pointer types passing 'char *' to parameter of type 'wchar_t *' (aka 'int *')
      [-Werror,-Wincompatible-pointer-types]
  Py_SetProgramName(argv[0]);
                    ^~~~~~~
/Users/doug/projects/py-sdl2/py3/include/python3.3m/pythonrun.h:25:45: note: passing argument to parameter here
PyAPI_FUNC(void) Py_SetProgramName(wchar_t *);
                                            ^
/Users/doug/env/src/main.c:10:23: error: incompatible pointer types passing 'char **' to parameter of type 'wchar_t **' (aka 'int **')
      [-Werror,-Wincompatible-pointer-types]
  PySys_SetArgv(argc, argv);
                      ^~~~
/Users/doug/projects/py-sdl2/py3/include/python3.3m/sysmodule.h:12:47: note: passing argument to parameter here
PyAPI_FUNC(void) PySys_SetArgv(int, wchar_t **);
                                              ^
/Users/doug/env/src/main.c:24:27: error: incompatible pointer types passing 'char **' to parameter of type 'wchar_t **' (aka 'int **')
      [-Werror,-Wincompatible-pointer-types]
  int rtn = Py_Main(argc, argv);
                          ^~~~
/Users/doug/projects/py-sdl2/py3/include/python3.3m/pythonrun.h:148:45: note: passing argument to parameter 'argv' here
PyAPI_FUNC(int) Py_Main(int argc, wchar_t **argv);
                                            ^
3 errors generated.
make[2]: *** [CMakeFiles/python.dir/src/main.c.o] Error 1
make[1]: *** [CMakeFiles/python.dir/all] Error 2
make: *** [all] Error 2

你可以从错误中看到,为wchar_t是用来代替字符*。

As you can see from the error, wchar_t is used instead of char *.

你是如何应该使用这个API?

How are you supposed to use this api?

我看到有这样做,例如的几个例子:
http://svn.python.org/projects/python/tags /r32rc2/Python/frozenmain.c

I see there are a few examples of doing this, for example: http://svn.python.org/projects/python/tags/r32rc2/Python/frozenmain.c

严重?

我29行的程序已经成为110行的怪物充满的#ifdefs的?

My 29 line program has to become a 110 line monster full of #ifdefs?

我误解,或者已经在python3 C API真正成为这个可笑难用?

Am I misunderstanding, or has the python3 c api really become this ridiculously difficult to use?

当然,我错过了一些明显的便利功能,可以实现这个要求,在一个简单,便携和跨平台的方式?

Surely I'm missing some obvious convenience function which does this for you, in a simple, portable and cross platform way?

推荐答案

似乎有没有简单的方法来做到这一点。

Seems there's no easy way to do this.

我来下最接近的一次。我将离开这个问题的含糊希望有人会来告诉我超级容易和简单的方法来做到这一点打开。

The closest I've come to below. I'll leave the question open in the vague hopes someone will come along and show me the super easy and simple way to do this.

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

int main(int argc, char *argv[]) {

  /* These have to be wchar_t */
  char *str_program_name = argv[0];
  char **str_argv = argv;

  /* For ever stupid reason, these don't need to be wchar_t * */
  char *_sys = "sys";
  char *_libdir = "lib";
  char *_path = "path";
  char *_dot = ".";

#if PY_MAJOR_VERSION >= 3
  wchar_t **_argv = nstrws_array(argc, str_argv);
  wchar_t *_program_name = nstrws_convert(str_program_name);
#else
  char **_argv = str_argv;
  char *_program_name = str_program_name;
#endif

  /* Setup */
  Py_SetProgramName(_program_name);
  Py_Initialize();

  /* Add local path */
#if PY_MAJOR_VERSION >= 3
  PyObject *sys = PyImport_ImportModule(_sys);
  PyObject *path = PyObject_GetAttrString(sys, _path);
  PyList_Append(path, PyBytes_FromString(_dot));
  PyList_Append(path, PyBytes_FromString(_libdir));
#else
  PyObject *sys = PyImport_ImportModule(_sys);
  PyObject *path = PyObject_GetAttrString(sys, _path);
  PyList_Append(path, PyString_FromString(_dot));
  PyList_Append(path, PyString_FromString(_libdir));
#endif

  /* Run the 'main' module */
  int rtn = Py_Main(argc, _argv);
  Py_Finalize();

#if PY_MAJOR_VERSION >= 3
  nstrws_dispose(argc, _argv);
  free(_program_name);
#endif

  return rtn;
}

使用:

/** Unix-like platform char * to wchar_t conversion. */
wchar_t *nstrws_convert(char *raw) {
  wchar_t *rtn = (wchar_t *) calloc(1, (sizeof(wchar_t) * (strlen(raw) + 1)));
  setlocale(LC_ALL,"en_US.UTF-8"); // Seriously, eat a bag of dicks python developers. Unless you do this python 3 crashes.
  mbstowcs(rtn, raw, strlen(raw));
  return rtn;
}

/** Dispose of an array of wchar_t * */
void nstrws_dispose(int count, wchar_t ** values) {
  for (int i = 0; i < count; i++) {
    free(values[i]);
  }
  free(values);
}

/** Convert an array of strings to wchar_t * all at once. */
wchar_t **nstrws_array(int argc, char *argv[]) {
  wchar_t **rtn = (wchar_t **) calloc(argc, sizeof(wchar_t *));
  for (int i = 0; i < argc; i++) {
    rtn[i] = nstrws_convert(argv[i]);
  }
  return rtn;
}

和对于Windows用户,如果需要的话:

and for windows users, if required:

#include <windows.h>

/** Windows char * to wchar_t conversion. */
wchar_t *nstrws_convert(char *raw) {
  int size_needed = MultiByteToWideChar(CP_UTF8, 0, raw, -1, NULL, 0);
  wchar_t *rtn = (wchar_t *) calloc(1, size_needed * sizeof(wchar_t));
  MultiByteToWideChar(CP_UTF8, 0, raw, -1, rtn, size_needed);
  return rtn;
}

这篇关于你如何使用命令行驱动的应用程序中的python3 C API?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆