2016-02-25 37 views
5

Per essere chiari, per eseguibili non intendo i byte letterali pronti per il processore. Ad esempio uno script bash, che è interpretato e non eseguibile, diventa eseguibile quando viene aggiunto uno shebang in alto che specifica che lo script deve essere eseguito da /bin/bash o /bin/sh o qualsiasi programma lo interpreti.È possibile eseguire qualsiasi linguaggio eseguibile?

Mi chiedevo se è possibile fare lo stesso con altri linguaggi di scripting? E se è così, è davvero facile come aggiungere uno shebang che fa riferimento al programma di interpretazione (ad esempio #!/usr/bin/python per uno script Python o #!/usr/local/bin/node per JavaScript)?

Mi chiedevo anche se è possibile fare con Java, che non è tecnicamente un linguaggio di scripting ma non è sicuramente eseguibile. Sembra che Java sia difficile perché l'utente non ha effettivamente l'opportunità di aggiungere uno shebang al file compilato.

risposta

3

Si può certamente creare un file:

#!/any/executable/program args 
...input goes here... 

si potrebbe fare con Java

#!/path/bin/java mainclass 
...this is System.in... 
+0

Ahh modo con Java i file .class dovranno essere conservati altrove e fa riferimento l'eseguibile ancora? –

+0

Sì, è corretto e dovresti assicurarti che il percorso di classe fosse corretto prima di eseguirlo. Quindi è più pratico usare solitamente uno sh script. –

+0

È interessante. Non sapevo che potresti passare argomenti anche dopo lo shebang.Immagino sia quello che ottengo per essere autodidatta haha. Risposta approvata! –

2

No. Non è possibile mettere un botto lei su qualsiasi script e sarà eseguito. Bash si basa sul fatto che il file con lo shebang ignora le righe che iniziano con #. Quindi qualsiasi linguaggio di scripting o codice byte che possa ignorare la prima riga con shebang funzionerà.

Se la tua lingua non supporta # come commento o ignora la prima riga deve passare attraverso un altro linguaggio di scripting che lo ignora.

Detto questo, è possibile avere script bash con blob binari in linea che possono essere chiamati. Gli installatori di giochi lo fanno.

+0

Come si usa un blob binario in uno script bash? –

+0

per esempio http://www.linuxjournal.com/content/add-binary-payload-your-shell-scripts – Alex

2

Invece di scrivere un sacco di codice per avere Java essere eseguibile in formato sorgente, avete alcune opzioni:

Usa Scala! Sapevi che Scala è costruita fuori da Java? Ha un interprete e un compilatore. Puoi eseguire uno script, una shell o compilare ed eseguirlo. Scala e Java funzionano perfettamente insieme. Entrambi compilano lo stesso bytecode ed eseguono su una JVM. Sì, il linguaggio sarebbe strano perché Scala è come un incrocio tra Java, R e Python, ma la maggior parte del linguaggio principale è invariato e tutti i pacchetti Java sono disponibili. Fai un tentativo a Scala. Se sei su Linux, potresti anche guardare Spark, anche per una macchina.

Se si insiste a utilizzare solo Java, è possibile creare un programma ibrido che faccia due cose (l'ho già fatto prima): compila il codice ed eseguilo. L'eseguibile o anche uno script di bash può fare il lavoro di prendere i file sorgente e renderli eseguibili. Se si sta cercando di creare una shell Java, è necessario creare un compilatore/caricatore di runtime dinamico, ma è sufficiente utilizzare ciò che Java/Oracle ci offre già. Immagina di inserire la sintassi Java da un file in cui inserisco una dichiarazione di stampa. Potresti avere qualsiasi cosa lì dentro che volevi fintanto che compila. Vedere questo esempio:

package util.injection; 

import java.io.File; 
import java.io.FileWriter; 
import java.io.IOException; 
import java.io.Writer; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.net.URLClassLoader; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 
import java.util.Locale; 
import javax.tools.Diagnostic; 
import javax.tools.DiagnosticCollector; 
import javax.tools.JavaCompiler; 
import javax.tools.JavaFileObject; 
import javax.tools.StandardJavaFileManager; 
import javax.tools.ToolProvider; 

public class Compiler { 

    static final long t0 = System.currentTimeMillis(); 

    public static void main(String[] args) { 
     StringBuilder sb = new StringBuilder(64); 
     String packageName = "util"; 
     String className = "HelloWorld"; 
     sb.append("package util;\n"); 
     sb.append("public class HelloWorld extends " + Function.class.getName() + " {\n"); 
     sb.append(" public void test() {\n"); 
     sb.append("  System.out.println(\"Hello from dynamic function!\");\n"); 
     sb.append(" }\n"); 
     sb.append("}\n"); 
     String code = sb.toString(); 

     String jarLibraryFile = "target/myprojectname.jar"; 

     Function dynFunction = code2class(packageName, className, code, jarLibraryFile); 
     dynFunction.test(); 
    } 

    public static Function code2class(String packageName, String className, String code, String jarLibraryFile) { 
     String wholeClassName = packageName.replace("/", ".") + "." + className; 
     String fileName = wholeClassName.replace(".", "/") + ".java";//"testcompile/HelloWorld.java"; 
     File javaCodeFile = new File(fileName); 
     string2file(javaCodeFile, code); 
     Function dynFunction = null; 
     try { 

      boolean success = compile(jarLibraryFile, javaCodeFile); 

      /** 
      * Load and execute 
      * ************************************************************************************************ 
      */ 
      System.out.println("Running... " + (System.currentTimeMillis() - t0) + " ms"); 
      Object obj = load(wholeClassName); 
      // Santity check 
      if (obj instanceof Function) { 
       dynFunction = (Function) obj; 
       // Run it 
       //Edit: call dynFunction.test(); to see something 
      } 
      System.out.println("Finished... " + (System.currentTimeMillis() - t0) + " ms"); 
     } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException exp) { 
      exp.printStackTrace(); 
     } 
     return dynFunction; 
    } 

    public static boolean compile(String jarLibraryFile, File javaCodeFile) throws IOException { 
     /** 
     * Compilation Requirements 
     * ******************************************************************************************** 
     */ 
     System.out.println("Compiling... " + (System.currentTimeMillis() - t0) + " ms"); 
     DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); 
     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
     StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); 

     // This sets up the class path that the compiler will use. 
     // I've added the .jar file that contains the DoStuff interface within in it... 
     List<String> optionList = new ArrayList<>(2); 
     optionList.add("-classpath"); 
     optionList.add(System.getProperty("java.class.path") + ";" + jarLibraryFile); 

     Iterable<? extends JavaFileObject> compilationUnit 
       = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(javaCodeFile)); 
     JavaCompiler.CompilationTask task = compiler.getTask(
       null, 
       fileManager, 
       diagnostics, 
       optionList, 
       null, 
       compilationUnit); 
     fileManager.close(); 

     /** 
     * ******************************************************************************************* 
     * Compilation Requirements * 
     */ 
     if (task.call()) { 
      return true; 
      /** 
      * *********************************************************************************************** 
      * Load and execute * 
      */ 
     } else { 
      for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) { 
       System.out.format("Error on line %d in %s%n", 
         diagnostic.getLineNumber(), 
         diagnostic.getSource().toUri()); 
       System.out.printf("Code = %s\nMessage = %s\n", diagnostic.getCode(), diagnostic.getMessage(Locale.US)); 

      } 
     } 
     return false; 
    } 

    public static void string2file(File outputFile, String code) { 
     if (outputFile.getParentFile().exists() || outputFile.getParentFile().mkdirs()) { 

      try { 
       Writer writer = null; 
       try { 
        writer = new FileWriter(outputFile); 
        writer.write(code); 
        writer.flush(); 
       } finally { 
        try { 
         writer.close(); 
        } catch (Exception e) { 
        } 
       } 
      } catch (IOException exp) { 
       exp.printStackTrace(); 
      } 
     } 
    } 

    public static Object load(String wholeClassName) throws IllegalAccessException, InstantiationException, ClassNotFoundException, MalformedURLException { 
     // Create a new custom class loader, pointing to the directory that contains the compiled 
     // classes, this should point to the top of the package structure! 
     URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("./").toURI().toURL()}); 
     // Load the class from the classloader by name.... 
     Class<?> loadedClass = classLoader.loadClass(wholeClassName); 
     // Create a new instance... 
     Object obj = loadedClass.newInstance(); 
     return obj; 
    } 

} 

..

package util.injection; 

public class Function { 

    private static final long serialVersionUID = 7526472295622776147L; 

    public void test() { 
       System.out.println("Hello from original Function!"); 
    } 

    public int getID() { 
     return -1; 
    } 

    public void apply(float[] img, int x, int y) { 

    } 

    public double dot(double[] x, double[] y) { 
      return 0; 
    } 
}