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.
我一直在使用自定义的构建来代替virtualenv,现在它是布里兰特。它需要更长的时间来构建,但它实际上是有效的,而且它从不出错。
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:
在一个简单的python包装器中,将一些特定的文件夹添加到库路径中,这是非常有用的。它的代码很简单:
#include
#include
#include
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;
}
So, moving to python3 is good right? So...
那么,移动到python3是很好的,对吧?所以…
I dutifully replaced the call to PyString_FromString() with PyByte_FromString() and tried to recompile, but it raises errors:
我使用PyByte_FromString()将调用替换为PyString_FromString(),并试图重新编译,但它会引起错误:
/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
As you can see from the error, wchar_t is used instead of char *.
从错误中可以看出,使用wchar_t代替char *。
How are you supposed to use this api?
你如何使用这个api?
I see there are a few examples of doing this, for example: http://svn.python.org/projects/python/tags/r32rc2/Python/frozenmain.c
我看到有一些这样做的例子,例如:http://svn.python.org/projects/python/tags/r32rc2/Python/frozenmain.c。
seriously?
严重吗?
My 29 line program has to become a 110 line monster full of #ifdefs?
我的29行程序必须变成一个110线怪物,满是#ifdefs?
Am I misunderstanding, or has the python3 c api really become this ridiculously difficult to use?
我是否误解了,或者python3 c api真的变得如此难以使用?
Surely I'm missing some obvious convenience function which does this for you, in a simple, portable and cross platform way?
我肯定错过了一些显而易见的便利功能,这是为你做的,在一个简单,便携,跨平台的方式?
6
The official recommended way of converting from char
to wchar_t
is by using Py_DecodeLocale
. Like this:
从char到wchar_t的官方推荐方法是使用Py_DecodeLocale。是这样的:
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
Py_SetProgramName(program);
2
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
#include
#include
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;
}
Using:
使用:
/** 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"); // 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
and for windows users, if required:
对于windows用户,如果需要:
#include
/** 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;
}
0
This is probably the wrong way to do it, never the less:
这可能是一种错误的做法,永远不会减少:
Py_SetProgramName((wchar_t*)argv[0]);
This fix stopped my code from complaining, haven't tested it to know how it handles args, but at least it compiles..
这个修复程序阻止了我的代码的抱怨,还没有测试它如何处理args,但至少它编译了。
0
I've found that this works at converting the char* to wchar_t* in the main function:
我发现,这可以将char*转换为wchar_t*,在main函数中:
wchar_t progname[FILENAME_MAX + 1];
mbstowcs(progname, argv[0], strlen(argv[0]) + 1);
Py_SetProgramName(progname);
If you are on unix use:
如果您在unix上使用:
#include "sys/param.h"