用Jython将我的Python脚本分发为JAR文件?
近两年来,我一直是一名Python程序员,我习惯于编写小脚本来自动完成我在办公室中需要做的一些重复任务。 现在,显然我的同事注意到了这一点,他们也想要这些脚本。
其中一些有Mac,有些Windows; 我在窗户上做了这些。 我调查了使用py2exe甚至py2app的可能性,使我的脚本的本地人,但他们从来没有满足我…
我知道他们所有的系统上都有JVM,所以我可以用Jython这样的东西给他们一个可执行的JAR文件吗?
这是多么可行……我的意思是,我不知道如何为Jython编写脚本,我写这些脚本的时候也不关心它,它会给出什么样的问题呢?
在Jython的wiki上的这篇文章中详细介绍了当前在jar中分发Python文件的最新技术: http : //wiki.python.org/jython/JythonFaq/DistributingJythonScripts
对于你的情况,我想你会想要把你安装Jython时获得的jython.jar文件压缩到Jython Lib目录中,然后压缩你的.py文件,然后在你的目录中添加一个__run__.py
文件启动逻辑(这个文件被Jython专门处理,当你用“java -jar”调用jar时,这个文件就会被执行)。
这个过程肯定是比较复杂的,所以我们(Jython开发者)需要提出一个很好的工具来自动执行这些任务,但是现在这些是最好的方法。 下面我在上面的文章的底部复制食谱(稍加修改以适应您的问题描述),给你一个解决scheme的感觉。
创build基本jar:
$ cd $JYTHON_HOME $ cp jython.jar jythonlib.jar $ zip -r jythonlib.jar Lib
将其他模块添加到jar中:
$ cd $MY_APP_DIRECTORY $ cp $JYTHON_HOME/jythonlib.jar myapp.jar $ zip myapp.jar Lib/showobjs.py # Add path to additional jar file. $ jar ufm myapp.jar othermanifest.mf
添加__run__.py
模块:
# Copy or rename your start-up script, removing the "__name__ == '__main__'" check. $ cp mymainscript.py __run__.py # Add your start-up script (__run__.py) to the jar. $ zip myapp.jar __run__.py # Add path to main jar to the CLASSPATH environment variable. $ export CLASSPATH=/path/to/my/app/myapp.jar:$CLASSPATH
在MS Windows上,设置CLASSPATH环境variables的最后一行,如下所示:
set CLASSPATH=C:\path\to\my\app\myapp.jar;%CLASSPATH%
或者,再次在MS Windows上,使用控制面板和系统属性来设置CLASSPATH环境variables。
运行应用程序:
$ java -jar myapp.jar mymainscript.py arg1 arg2
或者,如果您已将启动脚本添加到jar中,请使用以下选项之一:
$ java org.python.util.jython -jar myapp.jar arg1 arg2 $ java -cp myapp.jar org.python.util.jython -jar myapp.jar arg1 arg2 $ java -jar myapp.jar -jar myapp.jar arg1 arg2
双Jar是一种烦人的,所以如果你想避免这一点,得到更多的愉悦:
$ java -jar myapp.jar arg1
你将不得不做更多的工作,直到我们把这样的东西变成未来的Jython [更新:JarRunner是Jython 2.5.1的一部分]。 以下是一些自动查找__run__.py
Java代码,并运行它。 请注意,这是我第一次尝试这个课程。 让我知道是否需要改进!
package org.python.util; import org.python.core.imp; import org.python.core.PySystemState; public class JarRunner { public static void run(String[] args) { final String runner = "__run__"; String[] argv = new String[args.length + 1]; argv[0] = runner; System.arraycopy(args, 0, argv, 1, args.length); PySystemState.initialize(PySystemState.getBaseProperties(), null, argv); imp.load(runner); } public static void main(String[] args) { run(args); } }
我把这段代码放到了org.python.util包中,因为如果我们决定将它包含在未来的Jython中,那么这个代码就是这样。 为了编译它,你需要把jython.jar(或者你的myapp.jar)放到类path中,如:
$ javac -classpath myapp.jar org/python/util/JarRunner.java
然后,您需要将JarRunner.class添加到您的jar(类文件需要位于org / python / util / JarRunner.class中),然后在“org”目录中调用jar会将整个path导入到jar中。
$ jar uf org
将其添加到您将用于更新清单的文件中,好名称是manifest.txt:
Main-Class: org.python.util.JarRunner
然后更新jar的清单:
$ jar ufm myapp.jar manifest.txt
现在你应该可以像这样运行你的应用程序了:
$ java -jar myapp.jar
我遇到了一个类似的问题,我希望能够为我的jython应用程序创build简单的命令行调用,而不要求用户通过jython安装过程,并且能够让jython脚本在运行时向sys .path以包含核心Java代码。
# append Java library elements to path sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "lib", "poi-3.8-20120326.jar"))
当在命令行中明确运行“jython”启动器时,在Unix系统上,它只是运行一个大的shell脚本来正确地形成一个java命令行调用。 这个jython启动器似乎有一个依靠回到jython的核心安装,并通过某种魔术方式允许正确处理.jar文件在运行时从我的.py脚本中添加到sys.path。 你可以看到这个调用是什么,并通过以下方式阻止执行:
jython --print run_form.py java -Xmx512m -Xss1024k -Dfile.encoding=UTF-8 -classpath /Applications/jython2.5.2/jython.jar: -Dpython.home=/Applications/jython2.5.2 -Dpython.executable=/Applications/jython2.5.2/bin/jython org.python.util.jython run_form.py
但它仍然只是启动一个JVM并运行一个类文件。 所以我的目标是能够将这个java调用到我的发行版的lib目录中的一个独立的jython.jar中,这样用户就不需要执行任何额外的安装步骤来开始使用我的.py脚本实用程序。
java -Xmx512m -Xss1024k -classpath ../../lib/jython.jar org.python.util.jython run_form.py
麻烦的是,行为是不同的,我会得到这样的答复:
File "run_form.py", line 14, in <module> import xls_mgr File "/Users/test/Eclipse/workspace/test_code/py/test/xls_mgr.py", line 17, in <module> import org.apache.poi.hssf.extractor as xls_extractor ImportError: No module named apache
现在你可能会说我应该把jar文件添加到-classpath中,实际上我试过了,但是我会得到相同的结果。
将所有.class文件捆绑到jython.jar中的build议对我来说听起来都不是很吸引人。 这将是一个混乱,并将Java / Python混合应用程序绑定到jython发行版。 所以这个想法是不会飞的。 最后,经过大量的search,我在jython.org上find了1776号错误,这个错误已经被列为一年半的关键,但是我没有看到jython的最新更新包含了一个修复。 不过,如果您在使用jython包含单独的jar文件时遇到问题,则应该阅读此内容。
http://bugs.jython.org/issue1776
在那里,你会发现这个临时的解决方法。 在我的情况下,我拿起了Apache POI jar文件,并将它解压到它自己单独的lib目录中,然后修改sys.path条目来指向目录而不是jar:
sys.path.append('/Users/test/Eclipse/workspace/test_code/lib/poi_lib')
现在,当我通过java运行jython,引用我的本地jython.jar时,该实用程序运行得非常好。 现在我可以创build简单的脚本或batch file,为我的.py实用程序提供无缝的命令行体验,用户无需任何额外的安装步骤即可运行。
'jythonc'命令应该能够将.py源代码编译为JVM字节码,这将使其可以移植到任何Java安装中。 或者,我阅读: http : //hell.org.ua/Docs/oreilly/other2/python/0596001886_pythonian-chp-25-sect-3.html
为了以不需要本地Python安装的方式分发您的Python脚本,您也可以尝试使用Nuitka ,它基本上将您的Python代码转换为C ++代码,然后将其编译为真正的本机二进制文件。