使用 rpython 在 windows 下生成的程序无法运行
在 windows 用rpython编译出的文件总是无法运行,报
通过跟踪发现,rpython 每次都会将生成的C代码、Makefile 等放置在 %TEMP%\usession-release-2.0.x-17\testing_1 中(17是序号,每次都会自增),进去此目录,发现可执行文件是可以执行的——因为编译目录里是有manifest文件的。
Makefile 的生成是在 pypy-2.0.2-src\rpython\translator\c\genc.py 中的 CStandaloneBuilder::gen_makefile 中完成的,其间会调用平台相关的代码 pypy-2.0.2-src\rpython\translator\platform\windows.py 中的 MsvcPlatform::gen_makefile ,而 MsvcPlatform::gen_makefile 会试图在链接阶段嵌入manifest。代码如下——先判断编译器版本 self.version,如果大于等于 VC2005 就会在Makefile中输出 调用 mt.exe 嵌入manifest文件的步骤。
def gen_makefile(self, cfiles, eci, exe_name=None, path=None, shared=False): …… if self.version < 80: m.rule('$(TARGET)', '$(OBJECTS)', create_obj_response_file + [\ '$(CC_LINK) /nologo $(LDFLAGS) $(LDFLAGSEXTRA)' + objects + ' /out:$@ $(LIBDIRS) $(LIBS)', ]) else: m.rule('$(TARGET)', '$(OBJECTS)', create_obj_response_file + [\ '$(CC_LINK) /nologo $(LDFLAGS) $(LDFLAGSEXTRA)' + objects + ' $(LINKFILES) /out:$@ $(LIBDIRS) $(LIBS) /MANIFEST /MANIFESTFILE:$*.manifest', 'mt.exe -nologo -manifest $*.manifest -outputresource:$@;1', ])
至此,可以明白是 self.version 的值不正确。而执行命令 cl 获取编译器版本时,stderr的可能输出如下
中文版 VC2008输出
用于 80x86 的 Microsoft (R) 32 位 C/C++ 优化编译器 15.00.30729.01 版版权所有(C) Microsoft Corporation。保留所有权利。用法: cl [ 选项... ] 文件名... [ /link 链接选项... ]
英文版VC2010输出
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
usage: cl [ option... ] filename... [ /link linkoption... ]
可见是解析 stderr 时出问题了。如下所示,只需将 match 改search 即可
def __init__(self, cc=None, x64=False): self.x64 = x64 msvc_compiler_environ = find_msvc_env(x64) Platform.__init__(self, 'cl.exe') if msvc_compiler_environ: self.c_environ = os.environ.copy() self.c_environ.update(msvc_compiler_environ) # XXX passing an environment to subprocess is not enough. Why? os.environ.update(msvc_compiler_environ) # detect version of current compiler returncode, stdout, stderr = _run_subprocess(self.cc, '', env=self.c_environ) r = re.search(r'Microsoft.+C/C\+\+.+\s([0-9]+)\.([0-9]+).*', stderr) if r is not None: self.version = int(''.join(r.groups())) / 10 - 60 else:
见 https://bugs.pypy.org/issue1524