【问题标题】:How to create a command-line executable in Clojure如何在 Clojure 中创建命令行可执行文件
【发布时间】:2013-11-01 20:20:21
【问题描述】:

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

  1. 可以假设已安装 Java 并且 java 在路径中。
  2. 虽然在 Windows 上运行的解决方案将是一大优势,但您可以假设这一切都是在 Mac OS X 或 Ubuntu 等类 UNIX 操作系统上完成的。
  3. 可以在某种脚本中调用 Java。
  4. 可以使用用户可能安装或未安装的其他语言,例如 Ruby、Python 或 Perl。 All-bash 会很酷,因为我可以假设人们会这样做。
  5. 如果我必须使用某种工具来构建可执行的二进制文件,这没关系,但我不是在寻找期望使用 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 &lt;filename&gt; 来执行它。

我在使用这种方法时遇到的问题是 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。问题仍然存在:有没有更好、更简单的方法?我是否遗漏了一些明显的东西,或者这真的像看起来那么难?

【问题讨论】:

    标签: java ruby clojure


    【解决方案1】:

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

    【讨论】:

      【解决方案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 的目的。你只是通过一个额外的间接层来调用它。

      【讨论】:

      • 这个问题是它需要我在某个地方有一个单独的 jar 文件。我想这是可能的,但它有点不愉快。至于特定于平台的二进制文件,我认为大多数使用 JVM 的大型应用程序都是这样做的——例如考虑 Eclipse 或 jEdit。最后,我想要的只是独立的命令行脚本。
      • @door_number_three 你是对的——使用这种方法,你需要能够引用主机系统上的 jar。也许您也可以编写一个安装脚本,将 jar 放在您需要的地方,然后从您的脚本链接到它。
      【解决方案3】:

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

      有一个很好的教程来说明如何完成这个here

      【讨论】:

        【解决方案4】:

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

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

        然后

        chmod +x mytest
        

        然后简单地运行它

        ./mytest
        

        这有很多缺点。启动真的很慢。这个简单的 1 班轮运行时间超过 2 秒!你只会得到一个文件。可能这仅对最简单的事情有用。但是,如果您只是想快速做一些不是生产或测试的事情,这可能会很有用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-09-25
          • 2021-05-30
          • 1970-01-01
          • 2010-12-06
          • 2013-09-16
          • 1970-01-01
          相关资源
          最近更新 更多