IronPython:使用pyc.py编译的EXE无法导入模块"os

24 投票
2 回答
16387 浏览
提问于 2025-04-16 18:44

我有一个简单的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 个回答

8

我知道这个问题早就有人回答过了,但我花了很多时间才让我的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/

26

制作一个可以分发的Ironpython EXE文件有点复杂,特别是当你需要用到标准库里的东西时。我的一般做法是这样的:

我会把需要的所有标准库模块复制到一个文件夹里(通常我会把所有的模块都复制过去,以确保完整性),然后用这个脚本来生成我的EXE文件。在这个例子中,我有两个文件FredMain.pyFredSOAP.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')

撰写回答