如何在Clojure中创建命令行可执行文件

时间:2013-11-01 20:20:22

标签: java ruby clojure

我已经在Clojure中编写了一个程序,我想在命令行上执行它而不需要在命令行上专门调用java(例如java -jar)。我想要一个可执行文件,例如myprogram,它接受​​任何参数并运行我的程序。以下是一些可能使这更容易的事情:

  1. 可以假设安装了Java并且java在路径中。
  2. 虽然适用于Windows的解决方案是一个很好的解决方案,但您可以假设这一切都是在类似UNIX的操作系统(如Mac OS X或Ubuntu)上完成的。
  3. 可以在某种脚本中调用Java。
  4. 可以使用其他语言,例如Ruby,Python或Perl,用户可能已安装或未安装。 All-bash很酷,因为我可以假设人们有这个。
  5. 如果我必须使用某种工具来构建将要执行的二进制文件,这是可以的,但我不是在寻找希望使用GUI界面运行的.app或.exe文件(例如,Oracle的appbundler不是我在这里寻找的。)
  6. 我已经用一种方法走了很远的路,但我不得不怀疑是否有更好的方法。

    仅供参考:我已经尝试了

    我将在下面描述我的方法,但任何答案都不需要遵循这种方法。

    我所做的是创建一个名为makescript的lein插件,它生成一个uberjar,base64对其进行编码,并将其放在一个所谓的heredoc变量的Ruby脚本中,如下所示:

    # ...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编码的字符串不能解码为如果我使用Ruby,原始文件。这可能与两种语言之间的字符串本身(与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
    

    请注意原始大小接近但不相同,但编码版本差异很大。

    虽然这很令人费解但我想知道为什么会发生这种情况,我想我可以绕过这个问题,让makecript只生成uberjar并将路径传递给另一个Ruby脚本,然后将其编译为base64(后来解码) ,也使用Ruby)独立的JAR。问题仍然存在:是否有更好,更简单的方法?我错过了一些明显的东西,还是这看起来真的很难?

4 个答案:

答案 0 :(得分:4)

如果你真的想这样做,你可以在bash可执行文件中uuencode jar文件(或任何其他二进制文件),请参阅以下示例:Embed a Executable Binary in a shell script

答案 1 :(得分:2)

听起来您只是尝试使用更清晰的语法从脚本引导您的应用。这可能是最容易做到的:

创建一个名为myprogram的新bash脚本:

#!/usr/bin/bash
# pass whatever command line args you have down through the script
java -jar myjar.jar

赋予它执行权限

chmod +x myprogram

运行它

./myprogram (with whatever params)

如果你想摆脱./,你需要移动一下,以便你的PATH能够获取脚本。

请记住,您 未创建特定于平台的二进制可执行文件 。这样做几乎会破坏首先使用jvm的目的。你只是通过一个额外的间接层来调用它。

答案 2 :(得分:1)

如何将clojure作为解释性脚本运行。创建一个名为mytest的新文件:

#!/usr/bin/clojure
(print "hello world")

然后

chmod +x mytest

然后运行它

./mytest

这有很多缺点。开始真的很慢。这个简单的1班轮耗时2秒钟以上!您只会得到一个文件。可能这仅对最简单的事情有用。但是,如果您只是想快速做一些非生产性的事情或测试某些东西,这可能会很有用。

答案 3 :(得分:1)

现在GraalVM已经成熟了一些,您可能要考虑将应用程序编译为二进制可执行文件。

有一个很好的教程,介绍如何完成here