Ho scritto un programma in Clojure e mi piacerebbe eseguirlo sulla riga di comando senza specificamente invocare java sulla riga di comando (come java -jar
). Voglio un singolo file eseguibile, come ad esempio myprogram
, che accetta qualsiasi argomento ed esegue il mio programma. Ecco un paio di cose che potrebbero renderlo più semplice:Come creare un file eseguibile a riga di comando in Clojure
- Va bene supporre che Java sia installato e che
java
si trovi nel percorso. - Anche se una soluzione che funziona su Windows sarebbe un grande vantaggio, si può presumere che tutto ciò venga fatto su un sistema operativo simile a UNIX come Mac OS X o Ubuntu.
- È corretto invocare Java in uno script di qualche tipo.
- È OK utilizzare un altro linguaggio, come Ruby, Python o Perl, che l'utente può avere installato o meno. Tutto bash sarebbe bello perché posso supporre che le persone lo abbiano.
- Va bene se devo usare qualche tipo di strumento per costruire un binario che verrà eseguito, ma non sto cercando un file .app o .exe che si aspetta di operare con un'interfaccia GUI (quindi, ad esempio, l'appbundler di Oracle non è quello che sto cercando qui).
ho ottenuto abbastanza lontano su questa strada con un approccio, ma mi chiedo se c'è un modo migliore.
SOLO COME RIFERIMENTO: che cosa ho provato già
descriverò il mio avvicinamento al di sotto, ma nessuna risposta non c'è bisogno di seguire questa impostazione a tutti.
Quello che ho fatto è creare un plugin Lein chiamato makescript
che genera un uberjar, base64 codifica, e la colloca all'interno di uno script Ruby in una cosiddetta variabile heredoc, in questo modo:
# ...ruby script...
BASE64_JAR = <<-JAR_BOUNDARY
# [...base64 encoded file here...]
JAR_BOUNDARY
È dovrebbe quindi essere in grado di eseguire lo script ruby. Prenderà la variabile BASE64_JAR, la decodificherà, la inserirà in un file temporaneo e la eseguirà invocando java -jar <filename>
.
Il problema che sto avendo con questo approccio è quella biblioteca di Ruby base64
e clojure.data.codec.base64
librerie di Clojure sembra essere la produzione di diverse stringhe per rappresentare il vaso, e una stringa codificata dal Clojure non decodifica il file originale se uso di Ruby . Questo potrebbe avere qualcosa a che fare con la codifica delle stringhe stesse (associate forse a UTF-8) tra le due lingue. Qui ci sono Repl/sessioni IRB che illustrano la disconnessione:
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
Nota le dimensioni prime sono vicini, ma non è la stessa, ma le versioni codificate sono molto diverse.
Anche se questo è sconcertante e mi piacerebbe sapere perché questo accade, credo di poter aggirare il problema facendo makescript solo generare l'uberjar e passare il percorso di un altro script Ruby, che poi sarà base64 codifica (e più tardi decodificare, usando anche Ruby) il JAR standalone. La domanda continua: c'è un modo migliore, più semplice? Mi manca qualcosa di ovvio, o è davvero così difficile come sembra?
Che funziona benissimo! Risposta molto intelligente. –