IronPython:使用pyc.py编译的EXE无法导入模块"os
我有一个简单的IronPython脚本:
# Foo.py
import os
def main():
print( "Hello" )
if "__main__" == __name__:
main()
如果我用IronPython运行它,它可以正常工作并打印出Hello:
ipy Foo.py
根据这个网站上提供的说明IronPython - 如何编译exe,我使用以下命令将这个IronPython脚本编译成了一个EXE文件:
ipy pyc.py /main:Foo.py /target:exe
运行Foo.exe时出现了这个错误:
Unhandled Exception: IronPython.Runtime.Exceptions.ImportException: No module named os
at Microsoft.Scripting.Runtime.LightExceptions.CheckAndThrow(Object value)
at DLRCachedCode.__main__$1(CodeContext $globalContext, FunctionCode $functionCode)
at IronPython.Compiler.OnDiskScriptCode.Run()
at IronPython.Compiler.OnDiskScriptCode.Run(Scope scope)
at IronPython.Runtime.PythonContext.InitializeModule(String fileName, ModuleContext moduleContext, ScriptCode scriptC
ode, ModuleOptions options)
为什么找不到模块"os"呢?我该如何解决这个问题,以便能够得到一个可以正常工作的EXE文件?
(注意,这个问题和IronPython无法导入模块os的问题不同,因为如果我用ipy.exe
运行,脚本是可以正常工作的。)
2 个回答
我知道这个问题早就有人回答过了,但我花了很多时间才让我的exe文件正常工作。我发现了5个错误信息,其中有一个是关于导入的问题。为了让我的exe文件正常运行,我做了以下几件事:
1) 在发布文件夹中包含所有的IronPython dll文件(比如IronPython.dll、IronPython.Modules.dll等)。
2) 在发布文件夹中包含标准库的dll文件。
3) exe文件所在的路径不能有空格。
(比如这个路径:
C:\User1\MyDocuments\My Folder\deployFolder
应该改成这样:
C:\User1\MyDocuments\MyFolder\deployFolder)
4) 你的操作系统可能会阻止exe文件使用的某个dll,并给你一个“loadFromRemoteResource comutator error blablabla”的错误。要解决这个问题,你需要右键点击那个dll文件,然后在窗口的最后一行选择“解除阻止”。
5) 最后,别忘了把pyc生成的dll文件和你的exe文件一起放在一起(名字相同,只有扩展名不同)。
如果你需要更多细节,这里有一篇我写的文章:http://thesesergio.wordpress.com/2013/09/11/how-to-generate-and-use-a-exe-that-uses-net-dlls-with-ironpython-pyc-py/
制作一个可以分发的Ironpython EXE文件有点复杂,特别是当你需要用到标准库里的东西时。我的一般做法是这样的:
我会把需要的所有标准库模块复制到一个文件夹里(通常我会把所有的模块都复制过去,以确保完整性),然后用这个脚本来生成我的EXE文件。在这个例子中,我有两个文件FredMain.py和FredSOAP.py,它们会被编译成一个叫Fred_Download_Tool的EXE文件。
import sys
sys.path.append(r'C:\Program Files\IronPython 2.7\Lib')
sys.path.append(r'C:\Program Files\IronPython 2.7')
import clr
clr.AddReference('IronPython')
clr.AddReference('IronPython.Modules')
clr.AddReference('Microsoft.Scripting.Metadata')
clr.AddReference('Microsoft.Scripting')
clr.AddReference('Microsoft.Dynamic')
clr.AddReference('mscorlib')
clr.AddReference('System')
clr.AddReference('System.Data')
#
# adapted from os-path-walk-example-3.py
import os, glob
import fnmatch
import pyc
def doscopy(filename1):
print filename1
os.system ("copy %s .\\bin\Debug\%s" % (filename1, filename1))
class GlobDirectoryWalker:
# a forward iterator that traverses a directory tree
def __init__(self, directory, pattern="*"):
self.stack = [directory]
self.pattern = pattern
self.files = []
self.index = 0
def __getitem__(self, index):
while 1:
try:
file = self.files[self.index]
self.index = self.index + 1
except IndexError:
# pop next directory from stack
self.directory = self.stack.pop()
self.files = os.listdir(self.directory)
self.index = 0
else:
# got a filename
fullname = os.path.join(self.directory, file)
if os.path.isdir(fullname) and not os.path.islink(fullname) and fullname[-4:]<>'.svn':
self.stack.append(fullname)
if fnmatch.fnmatch(file, self.pattern):
return fullname
#Build StdLib.DLL
gb = glob.glob(r".\Lib\*.py")
gb.append("/out:StdLib")
#print ["/target:dll",]+gb
pyc.Main(["/target:dll"]+gb)
#Build EXE
gb=["/main:FredMain.py","FredSOAP.py","/target:exe","/out:Fred_Download_Tool"]
pyc.Main(gb)
#CopyFiles to Release Directory
doscopy("StdLib.dll")
doscopy("Fred_Download_Tool.exe")
doscopy("Fred_Download_.dll")
#Copy DLLs to Release Directory
fl = ["IronPython.dll","IronPython.Modules.dll","Microsoft.Dynamic.dll","Microsoft.Scripting.Debugging.dll","Microsoft.Scripting.dll","Microsoft.Scripting.ExtensionAttribute.dll","Microsoft.Scripting.Core.dll"]
for f in fl:
doscopy(f)
在我的脚本中,当我准备好编译时,我会添加以下内容。这可以让程序使用我DLL里的标准模块,而不是使用Python安装包里的模块。如果你想把这个程序分发给没有安装Python的人,这一步是必须的。只要确保在创建安装程序时包含必要的DLL文件就可以了。
#References to created DLL of python modules
clr.AddReference('StdLib')