【发布时间】:2013-11-01 20:20:21
【问题描述】:
我在 Clojure 中编写了一个程序,我想在命令行上执行它而不在命令行上专门调用 java(例如 java -jar)。我想要一个可执行文件,例如myprogram,它接受任何参数并运行我的程序。这里有几件事可能会使这更容易:
- 可以假设已安装 Java 并且
java在路径中。 - 虽然在 Windows 上运行的解决方案将是一大优势,但您可以假设这一切都是在 Mac OS X 或 Ubuntu 等类 UNIX 操作系统上完成的。
- 可以在某种脚本中调用 Java。
- 可以使用用户可能安装或未安装的其他语言,例如 Ruby、Python 或 Perl。 All-bash 会很酷,因为我可以假设人们会这样做。
- 如果我必须使用某种工具来构建可执行的二进制文件,这没关系,但我不是在寻找期望使用 GUI 界面操作的 .app 或 .exe 文件(例如,Oracle 的 appbundler不是我在这里寻找的东西)。
我已经通过一种方法在这条道路上走得很远,但我想知道是否有更好的方法。
仅供参考:我已经尝试过的方法
我将在下面描述我的方法,但任何答案都不需要遵循这种方法。
我所做的是创建一个名为 makescript 的 lein 插件,它生成一个 uberjar,base64 对其进行编码,并将其放置在一个 Ruby 脚本中的一个所谓的 heredoc 变量中,如下所示:
# ...ruby script...
BASE64_JAR = <<-JAR_BOUNDARY
# [...base64 encoded file here...]
JAR_BOUNDARY
然后您应该能够运行 ruby 脚本。它将获取 BASE64_JAR 变量,对其进行解编码,将其放置在一个临时文件中,然后通过调用 java -jar <filename> 来执行它。
我在使用这种方法时遇到的问题是 Ruby 的 base64 库和 Clojure 的 clojure.data.codec.base64 库似乎生成了不同的字符串来表示 jar,并且 Clojure 编码的字符串不会解码为原始文件,如果我使用红宝石。这可能与两种语言之间的字符串本身的编码(UTF-8 相关?也许)有关。以下是说明断开连接的 repl/irb 会话:
repl=> (def jar-contents (slurp "../target/myproj-0.1.0-SNAPSHOT-002-standalone.jar"))
repl=> (count jar-contents) ;; => 9433328
repl=> (def a-str (String. (clojure.data.codec.base64/encode (.getBytes jar-contents)) "UTF-8"))
repl=> (count a-str) ;; => 23265576
irb> f = File.open("target/pwgen-0.1.0-SNAPSHOT-002-standalone.jar", "r").read()
irb> p f.length # => 9657639
irb> b = Base64.encode64(f)
irb> p b.length # => 13564973
请注意,原始大小接近但不一样,但编码版本却大不相同。
虽然这很令人费解,我想知道为什么会发生这种情况,但我想我可以通过让 makescript 生成 uberjar 并将路径传递给另一个 Ruby 脚本,然后将 base64 编码(然后解码)来绕过这个问题, 也使用 Ruby) 独立的 JAR。问题仍然存在:有没有更好、更简单的方法?我是否遗漏了一些明显的东西,或者这真的像看起来那么难?
【问题讨论】: