Napisałem program w Clojure i chciałbym go wykonać w linii poleceń bez specyficznego wywoływania java w linii poleceń (np. java -jar
). Chcę jednego pliku wykonywalnego, takiego jak myprogram
, który akceptuje dowolne argumenty i uruchamia mój program. Oto kilka rzeczy, które mogą ułatwić to:Jak utworzyć plik wykonywalny wiersza poleceń w Clojure
- Można założyć, że Java jest zainstalowana i że na ścieżce znajduje się
java
. - Chociaż rozwiązanie działające w systemie Windows byłoby wielkim plusem, można założyć, że wszystko to dzieje się w systemie operacyjnym podobnym do UNIX, takim jak Mac OS X lub Ubuntu.
- Można wywołać Javę w jakimś skrypcie.
- Można używać innych języków, takich jak Ruby, Python lub Perl, które użytkownik zainstalował lub nie. All-bash byłoby fajne, ponieważ mogę założyć, że ludzie to mają.
- Jest OK, jeśli muszę użyć jakiegoś narzędzia do zbudowania binarnego, który będzie wykonywany, ale nie szukam pliku .app lub .exe, który oczekuje działania z interfejsem GUI (na przykład aplikacja Oracle Oracle nie jest tym, czego szukam tutaj).
Dostałem się dość daleko na tej ścieżce jednym podejściem, ale muszę się zastanowić, czy istnieje lepszy sposób.
tylko w celach: Co Próbowałem już
opiszę moje podejście poniżej, ale żadnych odpowiedzi nie trzeba stosować to podejście w ogóle.
Co mam zrobić, to stworzyć plugin Lein nazwie makescript
który generuje uberjar, base64 koduje je i umieszcza go wewnątrz skryptu Ruby w tzw zmiennej heredoc, tak:
# ...ruby script...
BASE64_JAR = <<-JAR_BOUNDARY
# [...base64 encoded file here...]
JAR_BOUNDARY
Ty powinien wtedy móc uruchomić skrypt ruby. Spowoduje to zmianę zmiennej BASE64_JAR, jej kodowanie, umieszczenie w pliku tymczasowym i wykonanie go przez wywołanie java -jar <filename>
.
Problem mam z tego podejścia jest to, że base64
biblioteki Ruby i clojure.data.codec.base64
biblioteki Clojure zdają się produkować różne struny do reprezentowania słoika, a ciąg zakodowany przez Clojure nie dekodować do oryginalnego pliku, jeśli mogę użyć Ruby . Może to mieć coś wspólnego z kodowaniem samych łańcuchów (może być związanych z UTF-8) pomiędzy tymi dwoma językami. Oto Repl/IRB sesje, które zilustrują odłączyć:
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
Uwaga surowe rozmiary są blisko, ale nie takie same, ale zakodowane wersje są bardzo różne.
Chociaż jest to zagadkowe i chciałbym się dowiedzieć, dlaczego tak się dzieje, myślę, że mogę ominąć problem poprzez napisanie po prostu konstruktora uberjara i przekazanie ścieżki do innego skryptu Ruby, który następnie będzie kodował base64 (i później dekodowanie, również przy użyciu Ruby) autonomicznego JAR. Pozostaje pytanie: czy istnieje lepszy, prostszy sposób? Czy brakuje mi czegoś oczywistego, czy jest to naprawdę tak trudne, jak się wydaje?
To działa świetnie! Bardzo sprytna odpowiedź. –