2013-11-01 7 views
5

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

  1. Va bene supporre che Java sia installato e che java si trovi nel percorso.
  2. 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.
  3. È corretto invocare Java in uno script di qualche tipo.
  4. È 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.
  5. 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?

risposta

2

Sembra che tu stia provando a riavviare la tua app da uno script usando una sintassi più pulita.Questo potrebbe essere fatto più facilmente in questo modo:

creare un nuovo script bash chiamato myprogram:

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

dare i permessi di esecuzione

chmod +x myprogram 

periodo è

./myprogram (with whatever params) 

Se vuoi liberarti dello ./ dovrai muovere le cose in giro così la sceneggiatura viene ripresa dal tuo PATH.

Ricordare che si è non creare un eseguibile binario specifico della piattaforma. Fare ciò equivale a sconfiggere lo scopo di usare jvm in primo luogo. Lo stavate invocando solo attraverso un ulteriore livello di riferimento indiretto.

+0

Il problema di questo è che mi richiede di avere un file jar separato da qualche parte. Suppongo che sia possibile, ma è un po 'spiacevole. Per quanto riguarda il binario specifico della piattaforma, penso che la maggior parte delle app di grandi dimensioni che usano la JVM facciano esattamente questo: pensando ad esempio ad Eclipse o jEdit. Alla fine, però, tutto ciò che voglio è uno script da riga di comando autonomo. –

+0

@door_number_three Hai ragione: con questo approccio, dovresti essere in grado di fare riferimento al jar sul sistema host. Forse potresti scrivere anche uno script di installazione che mette il barattolo nel punto in cui ti serve, e quindi collegalo a quello del tuo script. – yamafontes

Problemi correlati