Is it possible to make any language executable?

To be clear, with an executable, I don't mean literal bytes ready for the processor. For example, a bash script that is interpreted and not executed becomes executable when shebang is added to the beginning, which indicates that the script should run /bin/bash or /bin/sh , or any program will interpret it.

I was wondering if the same can be done with other scripting languages? And if so, is it really as simple as adding a shebang that references an interpreter (i.e. #!/usr/bin/python for a Python script or #!/usr/local/bin/node for JavaScript)?

I was also wondering if it is possible to do this with Java, which is not technically a scripting language, but is definitely not executable. It seems that Java will be difficult because the user has no way to add shebang to the compiled file.

+5
source share
3 answers

You can create a file:

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

You can do it with Java

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

No. It is impossible to put it on any script, and it will be executed. Bash relies on the shebang file to ignore lines starting with # . Therefore, any scripting language or byte code that can ignore the first line using shebang will work.

If your language does not support # as a comment or ignores, the first line should go through another scripting language that ignores this.

In doing so, you can have Bash scripts that have binary blob-inline that can be called. Game installers do this.

+2
source

Instead of writing a lot of code so that Java executes in its original form, you have several options:

Use Scala! Do you know that Scala is built in Java? It has an interpreter and compiler. You can run a script, shell, or compile and run it. Scala and Java work together. Both are compiled into a single bytecode and run on the JVM. Yes, the language will be strange, because Scala is like a crossroads between Java, R and Python, but most of the main language does not change and all Java packages are available. Try Scala to try. If you work on Linux, you can also take a look at Spark even on one machine.

If you insist on using Java only, you can create a hybrid program that does two things (I did it before): compile the code and run it. An executable file or even a bash script can do the work with the source files and make them executable. If you want to create a Java wrapper, you need to create a dynamic compiler / loader at runtime, but you just need to use what Java / Oracle already gives us. Imagine you are pasting Java syntax from a file into which I put a print statement. You can have anything if you want while it compiles. See this example:

 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; } } 
+2
source

Source: https://habr.com/ru/post/1243816/


All Articles