为 Windows Phone 8 编译 Python 已翻译 100%

oschina 投递于 2012/12/25 09:23 (共 8 段, 翻译完成于 12-26)
阅读 3907
收藏 1
1
加载中

介绍

Windows Phone 8(wp8) 支持本地编码,开发者可以直接用c或c++语言编写应用,并且有成功移植的案例.但是wp8和win32在应用程序接口方面也存在很多的不同。这些差异在许多分类中都存在,比如本地线程,同步(并行)函数,文件查找,库加载等等,这些差异为代码移植带来了很大的工作量。

李哲801
翻译于 2012/12/25 16:17
1
Python是一种动态脚本语言,有很多功能模块。它很容易学习和使用Python可以提高应用程序的灵活性而且现有的Python模块也可以用来加快研发过程由于Python动态语言,应用程序可以使用此功能来创建逻辑动态控制一些应用程序Python解释器由C编写由于WP8支持本机代码,我们可以在WP8上编译Python源代码使得在WP8使用Python的成为可能。
寂寞沙洲
翻译于 2012/12/26 09:42
1

由于WP8 API的限制python的一些源代码必须被改动使得编译成功。此外,一些APIs例如thread ,Windows的注册表并不支持不是所有的模块或功能,可以移植到WP8

本文讨论如何在WP8编译Python源代码源代码所做的改动给出了一个例子WP8本地应用程序中使用Python

寂寞沙洲
翻译于 2012/12/26 09:49
1

源代码的主要改动

线程相关函数

对于WP8不支持原生线程,在WP8线程相关的函数不能被编译因此,我们从工程中移除这些源代码文件,并且修改 “pyconfig.h”

/* Define if you want to compile in rudimentary thread support */
#undef WITH_THREAD 
从项目中删除这些源文件
modules\posixmodule
modules\mmapmodule 
modules\threadmodule
Python\thread.c 
timemodule.c的修改
#if !defined(ENV_WP)
static PyObject *
time_sleep(PyObject *self, PyObject *args)
{
    double secs;
    if (!PyArg_ParseTuple(args, "d:sleep", &secs))
        return NULL;
    if (floatsleep(secs) != 0)
        return NULL;
    Py_INCREF(Py_None);
    return Py_None;
}
#endif
#if !defined(ENV_WP)
    {"sleep",           time_sleep, METH_VARARGS, sleep_doc},
#endif 
 config.c的修改
#if !defined(ENV_WP)
    {"nt", initnt}, /* Use the NT os functions, not posix */
#endif
#if !defined(ENV_WP)
    {"mmap", initmmap},
#endif
#if !defined(ENV_WP)
    {"_winreg", init_winreg},
#endif
#if !defined(ENV_WP)
    {"_subprocess", init_subprocess},
#endif 


寂寞沙洲
翻译于 2012/12/26 09:54
1
由于不支持线程, os python模块不能正常工作, 所以导致 site.py 不能正确导入, 所以site.py应该被默认导入。

在pythonrun.c中

#if !defined(ENV_WP)
    if (!Py_NoSiteFlag)
        initsite(); /* Module site */
#endif 

修改 getenv 函数

wp8上的getenv函数不返回环境变量, 所以我们用一个新的getenv_win8函数替换这个函数, 新函数能返回PYTHONPATH 和 PYTHONHOME.

首先, 改变pydebug.h

extern char *getenv_win8(char *name);
#define Py_GETENV(s) (Py_IgnoreEnvironmentFlag ? NULL : getenv_win8(s)) 
新建文件 “Python_wp8.cpp”, 加入函数 getenv_win8,
bool GetInstall_Dir_win8(char *Buf,int BufSize)
{
    if( BufSize == 0 || Buf == NULL )
        return false;
    WideCharToMultiByte( CP_ACP, 0, Windows::ApplicationModel::Package::Current->InstalledLocation -> Path->Data(), -1, Buf, BufSize-1, NULL, NULL );
    Buf[BufSize-1] = 0;
    return true;
}
char *getenv_win8(char *name)
{
    char Buf[1024];
    static char RetBuf[1024];
    GetInstall_Dir_win8(Buf,1024);
    if( stricmp(name,"PYTHONPATH") == 0 ){
        sprintf(RetBuf,"%s\\python\\lib",Buf);
        return RetBuf;
    }else if( stricmp(name,"PYTHONHOME") == 0 ){
        sprintf(RetBuf,"%s\\python",Buf);
        return RetBuf;
    }else
        return NULL;
}  

note: Python_wp8.cpp 文件要用 windows runtime 编译.

寂寞沙洲
翻译于 2012/12/26 10:03
1

修改loadlibraryex 函数

首先, LoadLibraryEx 不能加载绝对路径的库, 所以在 LoadLibraryEx 函数之前 GetFullPathName 应该被调用. 第二, LoadPackagedLibrary 应该在 LoadLibraryEx 之外使用.

dynload_win.c的修改.

#if !defined(ENV_WP)
        old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
        if (GetFullPathName(pathname,
                            sizeof(pathbuf),
                            pathbuf,
                            &dummy)) {
            ULONG_PTR cookie = _Py_ActivateActCtx();
            /* XXX This call doesn't exist in Windows CE */
            hDLL = LoadLibraryEx(pathname, NULL,
                                 LOAD_WITH_ALTERED_SEARCH_PATH);
            _Py_DeactivateActCtx(cookie);
        }
        /* restore old error mode settings */
        SetErrorMode(old_mode);
#endif
#if defined(ENV_WP)
        {
            ULONG_PTR cookie = _Py_ActivateActCtx();
            /* XXX This call doesn't exist in Windows CE */
            MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, pathname, -1,wacModuleName, 512 );
            //hDLL = (HINSTANCE)LoadPackagedLibrary(wacModuleName,0);
            hDLL = (HINSTANCE)SRP_LoadPackage(wacModuleName);
            _Py_DeactivateActCtx(cookie);
        }
#endif

void  *SRP_LoadPackage(wchar_t *wacModuleName)
{
    return (void *)LoadPackagedLibrary(wacModuleName,0);
} 

寂寞沙洲
翻译于 2012/12/26 10:08
1
修改FindFirstFile 函数

FindFirstFile不支持, FindFirstFileEx 应该使用unicode 字符串. 因此 import.c 中的函数必须被修改.

static int
case_ok(char *buf, Py_ssize_t len, Py_ssize_t namelen, char *name)
{
/* Pick a platform-specific implementation; the sequence of #if's here should
 * match the sequence just above.
 */
/* MS_WINDOWS */
#if defined(MS_WINDOWS)
#if !defined(ENV_WP)
    WIN32_FIND_DATA data;
#else
    wchar_t wacFileName[512] ;
    char acFileName[512] ;
    WIN32_FIND_DATAW data;
#endif
    HANDLE h;
    if (Py_GETENV("PYTHONCASEOK") != NULL)
        return 1;
#if !defined(ENV_WP)
    h = FindFirstFile(buf, &data);
#else
    MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, buf, -1,wacFileName, 512 );
    h = FindFirstFileExW(wacFileName,FindExInfoStandard,&data,FindExSearchNameMatch,NULL, 0);
#endif
    if (h == INVALID_HANDLE_VALUE) {
        PyErr_Format(PyExc_NameError,
          "Can't find file for module %.100s\n(filename %.300s)",
          name, buf);
        return 0;
    }
    FindClose(h);
#if !defined(ENV_WP)
    return strncmp(data.cFileName, name, namelen) == 0;
#else
    WideCharToMultiByte( CP_ACP, 0, data.cFileName, -1, acFileName, 511, NULL, NULL );
    return strncmp(acFileName, name, namelen) == 0;
#endif 

寂寞沙洲
翻译于 2012/12/26 10:12
1
修改其他文件或函数.

有一些另外的修改请查看源代码.

wp8工程的全部源代码修改能从这下载 http://code.google.com/p/c-python-for-windows-phone8

WP8原生APP种使用python的例子

1. 新建工程

打开vs2012, 新建一个原生 windows phone 8工程, 例如:

2. 添加python27.dll 到这个工程, 设定它的 “content” 属性到 Yes.

3. 设定include directories 和 library search 路径

4. 添加python27.lib

5. 新建pytest.py, 并加入工程,设定它的 “content” 属性到 Yes.

def add(a,b):  
    return a + b

将被测试的python代码很简单, 计算两数相加的结果.

6. 生成c++ 代码调用python.

#include 
#if defined(_DEBUG)
#undef _DEBUG
#include "python.h"
#define _DEBUG
#else
#include "python.h"
#endif
void test()
{
    PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pRetVal; 
    Py_Initialize();  
    if ( !Py_IsInitialized() ){  
        return;  
    }  
    pName = PyString_FromString("pytest");  
    pModule = PyImport_Import(pName);  
    if ( !pModule ){  
        OutputDebugString(L"can't find pytest.py\n");
        return;  
    }  
    pDict = PyModule_GetDict(pModule);  
    if ( !pDict ){  
        return;  
    }  
    pFunc = PyDict_GetItemString(pDict, "add");  
    if ( !pFunc || !PyCallable_Check(pFunc) ) {  
        OutputDebugString(L"can't find function [add]\n");  
        return;  
    }  
    pArgs = PyTuple_New(2);  
    PyTuple_SetItem(pArgs, 0, Py_BuildValue("l",3));   
    PyTuple_SetItem(pArgs, 1, Py_BuildValue("l",4));  
    pRetVal = PyObject_CallObject(pFunc, pArgs);  
    char ResultBuf[512];
    wchar_t ResultBufW[512];
    sprintf_s(ResultBuf,512,"function return value : %ld\r\n", PyInt_AsLong(pRetVal));
    MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, ResultBuf, -1,ResultBufW, 512 );
    OutputDebugString(ResultBufW);  
    Py_DECREF(pName);  
    Py_DECREF(pArgs);  
    Py_DECREF(pModule);  
    Py_DECREF(pRetVal);  
    Py_Finalize();  
    return;  
} 
编译运行, 结果就会在输出窗口输出.
寂寞沙洲
翻译于 2012/12/26 10:26
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(3)

grail
grail
页面和以前不一样了。
用户已屏蔽
用户已屏蔽
这页面咋排的这样
我不叫大脸猫
我不叫大脸猫
这个碉堡了
返回顶部
顶部