├── hello-world ├── hello.lua └── hello.c ├── torch-test ├── torch-test.lua └── torch-test.c ├── .gitmodules ├── factorial ├── factorial.lua └── factorial.c ├── jni-example ├── factorial.lua ├── FactorialJNI.java ├── FactorialJNI.h ├── Makefile └── FactorialJNI.c ├── function-ref-example ├── factorial.lua ├── Makefile ├── LuaJNI.java ├── LuaJNI.h └── LuaJNI.c ├── simple-jni-example ├── HelloWorldJNI.java ├── HelloWorldJNI.c └── HelloWorldJNI.h ├── config-example ├── computation.lua ├── Makefile ├── ComputationJNI.java ├── ComputationJNI.h └── ComputationJNI.c ├── .gitignore └── README.md /hello-world/hello.lua: -------------------------------------------------------------------------------- 1 | print("Hello, World!") 2 | -------------------------------------------------------------------------------- /torch-test/torch-test.lua: -------------------------------------------------------------------------------- 1 | require('torch') 2 | 3 | function cosine(theta) 4 | return torch.cos(theta) 5 | end 6 | 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "torch-distro"] 2 | path = torch-distro 3 | url = https://github.com/klgraham/distro 4 | branch = master 5 | 6 | -------------------------------------------------------------------------------- /factorial/factorial.lua: -------------------------------------------------------------------------------- 1 | function factorial(n) 2 | local result = 1 3 | for i = 1, n do 4 | result = result * i 5 | end 6 | return result 7 | end 8 | -------------------------------------------------------------------------------- /jni-example/factorial.lua: -------------------------------------------------------------------------------- 1 | function factorial(n) 2 | local result = 1 3 | for i = 1, n do 4 | result = result * i 5 | end 6 | return result 7 | end 8 | -------------------------------------------------------------------------------- /function-ref-example/factorial.lua: -------------------------------------------------------------------------------- 1 | function factorial(n) 2 | local result = 1 3 | for i = 1, n do 4 | result = result * i 5 | end 6 | return result 7 | end 8 | -------------------------------------------------------------------------------- /simple-jni-example/HelloWorldJNI.java: -------------------------------------------------------------------------------- 1 | public class HelloWorldJNI 2 | { 3 | private native void hello(); 4 | 5 | public static void main(String[] args) 6 | { 7 | System.load(args[0]); 8 | new HelloWorldJNI().hello(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /simple-jni-example/HelloWorldJNI.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "HelloWorldJNI.h" 4 | 5 | JNIEXPORT void JNICALL Java_HelloWorldJNI_hello(JNIEnv *env, jobject thisObj) 6 | { 7 | printf("Hello, World!\n"); 8 | return; 9 | } 10 | -------------------------------------------------------------------------------- /config-example/computation.lua: -------------------------------------------------------------------------------- 1 | function factorial(n) 2 | local result = 1 3 | for i = 1, n do 4 | result = result * i 5 | end 6 | return result 7 | end 8 | 9 | -- computes $\sum_{i=m}^N i$ 10 | function sum(m) 11 | local result = 0 12 | for i = m, N do 13 | result = result + i 14 | end 15 | return result 16 | end 17 | -------------------------------------------------------------------------------- /jni-example/FactorialJNI.java: -------------------------------------------------------------------------------- 1 | public class FactorialJNI 2 | { 3 | private native int factorial(int n); 4 | 5 | public static void main(String[] args) 6 | { 7 | System.load(args[0]); 8 | int n = Integer.valueOf(args[1]); 9 | 10 | FactorialJNI jni = new FactorialJNI(); 11 | int result = jni.factorial(n); 12 | 13 | System.out.println(n + "! = " + result + "\n"); 14 | } 15 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | *.su 34 | 35 | # Java 36 | *.class 37 | *.jar 38 | target 39 | 40 | *.log 41 | -------------------------------------------------------------------------------- /simple-jni-example/HelloWorldJNI.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class HelloWorldJNI */ 4 | 5 | #ifndef _Included_HelloWorldJNI 6 | #define _Included_HelloWorldJNI 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: HelloWorldJNI 12 | * Method: hello 13 | * Signature: ()V 14 | */ 15 | JNIEXPORT void JNICALL Java_HelloWorldJNI_hello 16 | (JNIEnv *, jobject); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | #endif 22 | -------------------------------------------------------------------------------- /jni-example/FactorialJNI.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class FactorialJNI */ 4 | 5 | #ifndef _Included_FactorialJNI 6 | #define _Included_FactorialJNI 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: FactorialJNI 12 | * Method: factorial 13 | * Signature: (I)I 14 | */ 15 | JNIEXPORT jint JNICALL Java_FactorialJNI_factorial 16 | (JNIEnv *, jobject, jint); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | #endif 22 | -------------------------------------------------------------------------------- /function-ref-example/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | LUAFLAGS=-I/usr/local/include -I$(TORCH_HOME)/include -I$(TORCH_HOME)/include/TH -L/usr/local/lib -L$(TORCH_HOME)/lib -llua -lluaT -lm -shared 3 | CFLAGS=-I$(JAVA_HOME)/include $(LUAFLAGS) -I. -fPIC 4 | 5 | all: libfact.dylib 6 | 7 | libfact.dylib: LuaJNI.o 8 | $(CC) -o $@ $< $(CFLAGS) 9 | 10 | LuaJNI.o: LuaJNI.c LuaJNI.h 11 | $(CC) -c $< -o $@ $(CFLAGS) 12 | 13 | LuaJNI.h: LuaJNI.class 14 | javah LuaJNI 15 | 16 | LuaJNI.class: LuaJNI.java 17 | javac $< 18 | 19 | clean: 20 | rm *.o *.class *.dylib LuaJNI.h 21 | -------------------------------------------------------------------------------- /config-example/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | LUAFLAGS=-I/usr/local/include -I$(TORCH_HOME)/include -I$(TORCH_HOME)/include/TH -L/usr/local/lib -L$(TORCH_HOME)/lib -llua -lluaT -lm -shared 3 | CFLAGS=-I$(JAVA_HOME)/include $(LUAFLAGS) -I. -fPIC 4 | 5 | all: libcomputation.dylib 6 | 7 | libcomputation.dylib: ComputationJNI.o 8 | $(CC) -o $@ $< $(CFLAGS) 9 | 10 | ComputationJNI.o: ComputationJNI.c ComputationJNI.h 11 | $(CC) -c $< -o $@ $(CFLAGS) 12 | 13 | ComputationJNI.h: ComputationJNI.class 14 | javah ComputationJNI 15 | 16 | ComputationJNI.class: ComputationJNI.java 17 | javac $< 18 | 19 | clean: 20 | rm *.o *.class *.dylib ComputationJNI.h 21 | -------------------------------------------------------------------------------- /jni-example/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | LUAFLAGS=-I/usr/local/include -I$(TORCH_HOME)/include -L/usr/local/lib -L$(TORCH_HOME)/lib -llua -lm -shared 3 | CFLAGS=-I$(JAVA_HOME)/include $(LUAFLAGS) -I. -fPIC 4 | 5 | all: libfactorial.dylib 6 | 7 | libfactorial.dylib: FactorialJNI.o 8 | $(CC) -o $@ $< $(CFLAGS) 9 | 10 | FactorialJNI.o: FactorialJNI.c FactorialJNI.h 11 | $(CC) -c $< -o $@ $(CFLAGS) 12 | 13 | #luatorch.o: luatorch.c 14 | # $(CC) -c $< -o $@ $(CFLAGS) 15 | 16 | FactorialJNI.h: FactorialJNI.class 17 | javah FactorialJNI 18 | 19 | FactorialJNI.class: FactorialJNI.java 20 | javac $< 21 | 22 | clean: 23 | rm *.o *.class *.dylib FactorialJNI.h 24 | -------------------------------------------------------------------------------- /hello-world/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | int status; 9 | lua_State *L; 10 | 11 | L = luaL_newstate(); // open Lua 12 | if (!L) { 13 | return -1; // Checks that Lua started up 14 | } 15 | 16 | luaL_openlibs(L); // load Lua libraries 17 | 18 | status = luaL_loadfile(L, "hello.lua"); // load Lua script 19 | int ret = lua_pcall(L, 0, 0, 0); // tell Lua to run the script 20 | if (ret != 0) { 21 | fprintf(stderr, "%s\n", lua_tostring(L, -1)); // tell us what mistake we made 22 | return 1; 23 | } 24 | 25 | lua_close(L); // Close Lua 26 | return 0; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /factorial/factorial.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | lua_State *L; 10 | 11 | L = luaL_newstate(); // open Lua 12 | luaL_openlibs(L); // load Lua libraries 13 | int n = atoi(argv[1]); 14 | 15 | luaL_loadfile(L, "factorial.lua"); 16 | lua_pcall(L, 0, 0, 0); // Execute script once to create and assign functions 17 | 18 | lua_getglobal(L, "factorial"); // function to be called 19 | lua_pushinteger(L, n); // push argument 20 | 21 | if (lua_pcall(L, 1, 1, 0) != 0) // 1 argument, 1 return value 22 | { 23 | fprintf(stderr, "%s\n", lua_tostring(L, -1)); 24 | return 1; 25 | } 26 | 27 | int result = lua_tointeger(L, -1); 28 | lua_pop(L, 1); // pop returned value 29 | printf("%d! is %d\n", n, result); 30 | 31 | lua_close(L); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /config-example/ComputationJNI.java: -------------------------------------------------------------------------------- 1 | 2 | import java.lang.Throwable; 3 | 4 | public class ComputationJNI 5 | { 6 | private native int sum(int m); 7 | private native String factorial(int n); 8 | private native void startLua(); 9 | private native void closeLua(); 10 | 11 | public ComputationJNI() 12 | { 13 | this.startLua(); 14 | } 15 | 16 | @Override 17 | protected void finalize() throws Throwable 18 | { 19 | this.closeLua(); 20 | } 21 | 22 | public static void main(String[] args) 23 | { 24 | System.load(args[0]); 25 | int n = Integer.valueOf(args[1]); 26 | 27 | ComputationJNI jni = new ComputationJNI(); 28 | String fact = jni.factorial(n); 29 | System.out.println(n + "! = " + fact + "\n"); 30 | int sum = -1; 31 | 32 | for (int m = 0; m < 10; m++) 33 | { 34 | sum = jni.sum(m); 35 | System.out.println("Sum(" + m + ", " + fact + ") = " + sum); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /torch-test/torch-test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | lua_State *L; 10 | 11 | L = luaL_newstate(); // open Lua 12 | luaL_openlibs(L); // load Lua libraries 13 | float radians = atof(argv[1]); 14 | 15 | luaL_loadfile(L, "torch-test.lua"); 16 | lua_pcall(L, 0, 0, 0); // Execute script once to create and assign functions 17 | 18 | lua_getglobal(L, "cosine"); // function to be called 19 | lua_pushnumber(L, radians); // push argument 20 | 21 | if (lua_pcall(L, 1, 1, 0) != 0) // 1 argument, 1 return value 22 | { 23 | fprintf(stderr, "%s\n", lua_tostring(L, -1)); 24 | return 1; 25 | } 26 | 27 | float result = lua_tonumber(L, -1); 28 | lua_pop(L, 1); // pop returned value 29 | printf("Cos(%f) = %f\n", radians, result); 30 | 31 | lua_close(L); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /function-ref-example/LuaJNI.java: -------------------------------------------------------------------------------- 1 | 2 | import java.lang.Throwable; 3 | 4 | public class LuaJNI 5 | { 6 | // loads function defined in scriptPath and returns registry reference 7 | private native int getFunctionRef(String scriptPath); 8 | 9 | // Apply function at Lua registry index ref to n 10 | private native int apply(int ref, int n); 11 | private native void startLua(); 12 | private native void closeLua(); 13 | 14 | public LuaJNI() 15 | { 16 | this.startLua(); 17 | } 18 | 19 | @Override 20 | protected void finalize() throws Throwable 21 | { 22 | this.closeLua(); 23 | } 24 | 25 | public static void main(String[] args) 26 | { 27 | System.load(args[0]); 28 | LuaJNI lua = new LuaJNI(); 29 | 30 | int ref = lua.getFunctionRef("factorial.lua"); 31 | System.out.println("Function ref: " + ref); 32 | 33 | for (int m = 0; m < 10; m++) 34 | { 35 | int fact = lua.apply(ref, m); 36 | System.out.println(m + "! = " + fact); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /function-ref-example/LuaJNI.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class LuaJNI */ 4 | 5 | #ifndef _Included_LuaJNI 6 | #define _Included_LuaJNI 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: LuaJNI 12 | * Method: getFunctionRef 13 | * Signature: (Ljava/lang/String;)I 14 | */ 15 | JNIEXPORT jint JNICALL Java_LuaJNI_getFunctionRef 16 | (JNIEnv *, jobject, jstring); 17 | 18 | /* 19 | * Class: LuaJNI 20 | * Method: apply 21 | * Signature: (II)I 22 | */ 23 | JNIEXPORT jint JNICALL Java_LuaJNI_apply 24 | (JNIEnv *, jobject, jint, jint); 25 | 26 | /* 27 | * Class: LuaJNI 28 | * Method: startLua 29 | * Signature: ()V 30 | */ 31 | JNIEXPORT void JNICALL Java_LuaJNI_startLua 32 | (JNIEnv *, jobject); 33 | 34 | /* 35 | * Class: LuaJNI 36 | * Method: closeLua 37 | * Signature: ()V 38 | */ 39 | JNIEXPORT void JNICALL Java_LuaJNI_closeLua 40 | (JNIEnv *, jobject); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | #endif 46 | -------------------------------------------------------------------------------- /jni-example/FactorialJNI.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "FactorialJNI.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | lua_State* initlua(); 13 | 14 | lua_State* init_lua() 15 | { 16 | lua_State *L; 17 | L = luaL_newstate(); 18 | 19 | if (!L) 20 | { 21 | fprintf(stderr, "%s\n", "Cannot create new Lua state!"); 22 | exit(-1); 23 | } 24 | luaL_openlibs(L); 25 | return L; 26 | } 27 | 28 | JNIEXPORT jint JNICALL Java_FactorialJNI_factorial(JNIEnv *env, jobject thisObj, jint n) 29 | { 30 | lua_State* L = init_lua(); 31 | jint result; 32 | luaL_loadfile(L, "factorial.lua"); 33 | lua_pcall(L, 0, 0, 0); 34 | lua_getglobal(L, "factorial"); 35 | lua_pushnumber(L, (int)n); 36 | 37 | if (lua_pcall(L, 1, 1, 0) != 0) 38 | { 39 | fprintf(stderr, "%s\n", lua_tostring(L, -1)); 40 | return 1; 41 | } 42 | 43 | result = (jint)lua_tonumber(L, -1); 44 | lua_pop(L, 1); 45 | lua_close(L); 46 | return result; 47 | } 48 | -------------------------------------------------------------------------------- /config-example/ComputationJNI.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class ComputationJNI */ 4 | 5 | #ifndef _Included_ComputationJNI 6 | #define _Included_ComputationJNI 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: ComputationJNI 12 | * Method: sum 13 | * Signature: (I)I 14 | */ 15 | JNIEXPORT jint JNICALL Java_ComputationJNI_sum 16 | (JNIEnv *, jobject, jint); 17 | 18 | /* 19 | * Class: ComputationJNI 20 | * Method: factorial 21 | * Signature: (I)Ljava/lang/String; 22 | */ 23 | JNIEXPORT jstring JNICALL Java_ComputationJNI_factorial 24 | (JNIEnv *, jobject, jint); 25 | 26 | /* 27 | * Class: ComputationJNI 28 | * Method: startLua 29 | * Signature: ()V 30 | */ 31 | JNIEXPORT void JNICALL Java_ComputationJNI_startLua 32 | (JNIEnv *, jobject); 33 | 34 | /* 35 | * Class: ComputationJNI 36 | * Method: closeLua 37 | * Signature: ()V 38 | */ 39 | JNIEXPORT void JNICALL Java_ComputationJNI_closeLua 40 | (JNIEnv *, jobject); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | #endif 46 | -------------------------------------------------------------------------------- /function-ref-example/LuaJNI.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "LuaJNI.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | const char* convert_jstring(JNIEnv *env, jstring s); 14 | 15 | 16 | lua_State *L; 17 | 18 | 19 | JNIEXPORT void JNICALL Java_LuaJNI_startLua(JNIEnv *env, jobject thisObj) 20 | { 21 | L = luaL_newstate(); 22 | 23 | if (!L) { 24 | fprintf(stderr, "%s\n", "Cannot create new Lua state!"); 25 | exit(-1); 26 | } 27 | luaL_openlibs(L); 28 | } 29 | 30 | 31 | JNIEXPORT void JNICALL Java_LuaJNI_closeLua(JNIEnv *env, jobject thisObj) 32 | { 33 | lua_close(L); 34 | } 35 | 36 | 37 | JNIEXPORT jint JNICALL Java_LuaJNI_apply(JNIEnv *env, jobject thisObj, jint functionRef, jint n) 38 | { 39 | // push function on the stack from the registry 40 | lua_rawgeti(L, LUA_REGISTRYINDEX, (int)functionRef); 41 | lua_pushinteger(L, (int)n); // push parameter onto stack 42 | 43 | if (lua_pcall(L, 1, 1, 0) != 0) { 44 | fprintf(stderr, "%s\n", lua_tostring(L, -1)); 45 | luaT_stackdump(L); 46 | exit(-1); 47 | } 48 | 49 | int result = lua_tointeger(L, -1); 50 | lua_pop(L, 1); // pop returned value 51 | return (jint)result; 52 | } 53 | 54 | 55 | JNIEXPORT jint JNICALL Java_LuaJNI_getFunctionRef(JNIEnv *env, jobject thisObj, jstring scriptPath) 56 | { 57 | const char *script = convert_jstring(env, scriptPath); 58 | 59 | luaL_dofile(L, script); // Load the function 60 | lua_getglobal(L, "factorial"); // place it on the stack 61 | 62 | // store function in the registry and return reference 63 | int ref = luaL_ref(L, LUA_REGISTRYINDEX); 64 | 65 | return (jint)ref; 66 | } 67 | 68 | /* converts a JNI string into a char pointer */ 69 | const char* convert_jstring(JNIEnv *env, jstring s) 70 | { 71 | const char *c_string = (*env)->GetStringUTFChars(env, s, NULL); 72 | if (!c_string) 73 | { 74 | fprintf(stderr, "%s\n", "Failure converting JNI string to C string"); 75 | return NULL; 76 | } 77 | return c_string; 78 | } 79 | -------------------------------------------------------------------------------- /config-example/ComputationJNI.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ComputationJNI.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | lua_State *L; 14 | 15 | 16 | JNIEXPORT void JNICALL Java_ComputationJNI_startLua(JNIEnv *env, jobject thisObj) 17 | { 18 | L = luaL_newstate(); 19 | 20 | if (!L) 21 | { 22 | fprintf(stderr, "%s\n", "Cannot create new Lua state!"); 23 | exit(-1); 24 | } 25 | luaL_openlibs(L); 26 | } 27 | 28 | 29 | JNIEXPORT void JNICALL Java_ComputationJNI_closeLua(JNIEnv *env, jobject thisObj) 30 | { 31 | lua_close(L); 32 | } 33 | 34 | 35 | JNIEXPORT jstring JNICALL Java_ComputationJNI_factorial(JNIEnv *env, jobject thisObj, jint n) 36 | { 37 | // load factorial function from script onto stack 38 | luaL_loadfile(L, "computation.lua"); 39 | lua_pcall(L, 0, 0, 0); 40 | lua_getglobal(L, "factorial"); 41 | 42 | lua_pushnumber(L, (int)n); // push parameter onto stack 43 | 44 | if (lua_pcall(L, 1, 1, 0) != 0) 45 | { 46 | fprintf(stderr, "%s\n", lua_tostring(L, -1)); 47 | luaT_stackdump(L); 48 | exit(-1); 49 | } 50 | 51 | // pop output off stack and store as a global variable 52 | lua_setglobal(L, "N"); 53 | 54 | jstring result = (*env)->NewStringUTF(env, "N"); // pass global var name to Java 55 | printf("Lua global var: %s", "N"); 56 | return result; 57 | } 58 | 59 | 60 | JNIEXPORT jint JNICALL Java_ComputationJNI_sum(JNIEnv *env, jobject thisObj, jint m) 61 | { 62 | // convert name of global var holding function input to C string 63 | // const char *var_name = (*env)->GetStringUTFChars(env, n, NULL); 64 | // fprintf(stderr, "Global name: %s", var_name); 65 | 66 | // load factorial function from script onto stack 67 | luaL_loadfile(L, "computation.lua"); 68 | lua_pcall(L, 0, 0, 0); 69 | lua_getglobal(L, "sum"); 70 | lua_pushnumber(L, (int)m); 71 | 72 | if (lua_pcall(L, 1, 1, 0) != 0) 73 | { 74 | fprintf(stderr, "%s\n", lua_tostring(L, -1)); 75 | luaT_stackdump(L); 76 | return 1; 77 | } 78 | 79 | // convert result to Java int 80 | jint result = (jint)lua_tonumber(L, -1); 81 | lua_pop(L, 1); // remove from stack 82 | 83 | // (*env)->ReleaseStringUTFChars(env, n, var_name); // release mem from C string 84 | return result; // return int to Java 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lua-c-embedding 2 | 3 | Here are some notes/instructions for embedding Lua in C. Initially, we follow along with [Marek Vavrusa's blog post](https://en.blog.nic.cz/2015/08/12/embedding-luajit-in-30-minutes-or-so/). Later, we move beyond and see how to interact with things in Torch. 4 | 5 | Note: This was initially setup to embed the LuaJIT, but I then discovered the issue with building 64-bit LuaJIT library to use with the JNI. So, I switched to plain Lua instead. 6 | 7 | ### Install Torch and Lua 8 | 9 | This repo includes the Torch distribution. Installation instrutions follow: 10 | 11 | - ```git clone https://github.com/klgraham/luajit-c-embedding.git ~/lua-c-embedding --recursive``` 12 | - ```cd ~/lua-c-embedding/torch-distro``` 13 | - install dependencies: ```bash install-deps``` 14 | - install Lua, LuaRocks, and Torch: ```TORCH_LUA_VERSION=LUA51 ./install.sh``` 15 | - ```cd ..``` 16 | - creating an environment variable ```$TORCH_HOME``` pointing to your torch installation, which is ```~/lua-c-embedding/torch-distro/install```. Note that if you skip this step, you'll need to update the makefiles in the JNI examples. 17 | 18 | ## Hello, World! 19 | 20 | In the hello-world directory you'll notice a Lua script named hello.lua which contains ```print('Hello, World!')``` and a C file, hello.c, which looks like this (modified from the above blog post): 21 | 22 | ``` 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | int main() 29 | { 30 | int status; 31 | lua_State *L; 32 | 33 | L = luaL_newstate(); // open Lua 34 | if (!L) { 35 | return -1; // Checks that Lua started up 36 | } 37 | 38 | luaL_openlibs(L); // load Lua libraries 39 | 40 | status = luaL_loadfile(L, argv[1]); // load Lua script 41 | int ret = lua_pcall(L, 0, 0, 0); // tell Lua to run the script 42 | if (ret != 0) { 43 | fprintf(stderr, "%s\n", lua_tostring(L, -1)); // tell us what mistake we made 44 | return 1; 45 | } 46 | 47 | lua_close(L); // Close Lua 48 | return 0; 49 | } 50 | ``` 51 | 52 | To compile the C, use: 53 | 54 | ```gcc hello.c -pagezero_size 10000 -image_base 100000000 -I$TORCH_HOME/include -I/usr/local/include -L/usr/local/lib -L$TORCH_HOME/lib -llua -lm -o hello.out```, noting that ```-pagezero_size 10000 -image_base 100000000``` only needs to be included on macOS systems. Also note how the LuaJIT include directory has been included in the compiler search path. 55 | 56 | You can now execute the Lua script with ```./hello.out hello.lua```. 57 | 58 | ### Understanding the C Code 59 | 60 | To interact with Lua from C we will use [Lua's C API](http://www.lua.org/pil/24.1.html). See http://pgl.yoyo.org/luai/i/_ for great documentation on the functions in Lua's C API. Let's look at the each part of hello-luajit.c. 61 | 62 | - ```luaL_newstate```: Starts up Lua and returns a new Lua state 63 | - ```luaL_openlibs```: loads the Lua standard libraries 64 | - ```luaL_loadfile```: Loads the Lua script 65 | - ```lua_pcall```: runs the Lua script and returns an error code 66 | - ```lua_close```: closes Lua 67 | 68 | ## Using the Lua Stack 69 | 70 | Lua uses a stack to exchange values with C. To get a value from Lua, you call Lua to push the value onto the stack. To pass a value from C to Lua, you call Lua to push the value onto the stack and then pop the value. When pushing a value onto the stack, it's important to know if the stack has room for the new value. The lua-users wiki has [a nice example of this](http://lua-users.org/wiki/SimpleLuaApiExample). Let's look a couple of examples. 71 | 72 | ### Example 1 73 | 74 | Suppose we want to compute the factorial of a number in Lua and make the result of the computation available in C. Go into the ```factorial``` directory. The Lua code is in the file factorial.lua: 75 | 76 | ``` 77 | function factorial(n) 78 | local result = 1 79 | for i = 1, n do 80 | result = result * i 81 | end 82 | return result 83 | end 84 | ``` 85 | 86 | From C, we'll call factorial.lua and then get the result from the Lua stack and print to stdout. 87 | 88 | ``` 89 | #include 90 | #include 91 | #include 92 | #include 93 | #include 94 | 95 | int main(int argc, char *argv[]) 96 | { 97 | lua_State *L; 98 | 99 | L = luaL_newstate(); // open Lua 100 | luaL_openlibs(L); // load Lua libraries 101 | int n = atoi(argv[1]); 102 | 103 | luaL_loadfile(L, "factorial.lua"); 104 | lua_pcall(L, 0, 0, 0); // Execute script once to create and assign functions 105 | 106 | lua_getglobal(L, "factorial"); // function to be called 107 | lua_pushnumber(L, n); // push argument 108 | 109 | if (lua_pcall(L, 1, 1, 0) != 0) // 1 argument, 1 return value 110 | { 111 | fprintf(stderr, "%s\n", lua_tostring(L, -1)); 112 | return 1; 113 | } 114 | 115 | int result = lua_tonumber(L, -1); 116 | lua_pop(L, 1); // pop returned value 117 | printf("%d! is %d\n", n, result); 118 | 119 | lua_close(L); 120 | return 0; 121 | } 122 | ``` 123 | 124 | This example is simple: 125 | 126 | 1. First, we load the Lua file containing the factorial function 127 | - Call ```lua_pcall``` to execute the script and create the functions 128 | - Call ```lua_getglobal``` to specify which function you wish to call 129 | - Push the function arguments to the stack, in order 130 | - Call ```lua_pcall``` again, specifying the number of arguments and return values 131 | - Use ```lua_tointeger``` to get the return value from the top of the stack 132 | 133 | You'll notice that at the end we pop the returned value from the stack with ```lua_pop```. For such a simple example, this is not needed since we're killing Lua afterwards, but for more complex uses you'll definitely want to clean up the stack before moving on. 134 | 135 | You can compile with ```gcc factorial.c -pagezero_size 10000 -image_base 100000000 -I$TORCH_HOME/include -I/usr/local/include -L/usr/local/lib -L$TORCH_HOME/lib -llua -lm -o fact.out```. You can run with ```./fact.out ``` 136 | 137 | ### Example 2 138 | 139 | Now we'll use Torch to compute the trace of a matrix. For this, we'll simply execute a Lua script that requires Torch: 140 | 141 | ``` 142 | require('torch') 143 | 144 | function cosine(theta) 145 | return torch.cos(theta) 146 | end 147 | ``` 148 | 149 | This example is functionally identical to the previous one. You should be able to do this on your own now. If you run into any trouble, just look at torch-test.c. 150 | 151 | ## Using Lua From Java 152 | 153 | 154 | 155 | This requires the JNI. So, first, we'll look at how to use it for a simple example. 156 | 157 | ### Hello, World, v2.0 158 | 159 | First, we make a Java class, HelloWorldJNI.java, that loads a native (C) library, helloworld, that contains a method ```hello()```. 160 | 161 | ``` 162 | public class HelloWorldJNI 163 | { 164 | private native void hello(); 165 | 166 | public static void main(String[] args) 167 | { 168 | System.load(args[0]); 169 | new HelloWorldJNI().hello(); 170 | } 171 | } 172 | ``` 173 | 174 | Next steps are to compile the java code with ```javac HelloWorldJNI.java``` to get the a class file, HelloWorld.class, and then generate the JNI header file with ```javah HelloWorldJNI```. 175 | 176 | Then we create the JNI C implementation, HelloWorldJNI.c: 177 | 178 | ``` 179 | #include 180 | #include 181 | #include "HelloWorldJNI.h" 182 | 183 | JNIEXPORT void JNICALL Java_HelloWorldJNI_hello(JNIEnv *env, jobject thisObj) 184 | { 185 | printf("Hello, World!\n"); 186 | return; 187 | } 188 | ``` 189 | 190 | Now we need to compile the C code and link everything up. For this we can use: 191 | 192 | ```gcc -I"$JAVA_HOME/include" -shared -o libhelloworld.dylib HelloWorldJNI.c``` 193 | 194 | Notice that we're including the location of JAVA_HOME/include, are creating a shared library, and are naming the library libhelloworld.dylib. To run the java application, you use ```java HelloWorldJNI ```. 195 | 196 | ### Using Torch from Java 197 | 198 | We're going to adapt the earlier example where we compute the factorial of a number. This is on the jni-example branch. You can build and run in the ```jni-example``` directory by using this: 199 | 200 | ```make && java FactorialJNI ``` 201 | 202 | 203 | Note, there is an issue using 64-bit LuaJIT on macOS: 204 | 205 | - http://comments.gmane.org/gmane.comp.lang.lua.luajit/4817 206 | - http://stackoverflow.com/questions/14840569/sigsegv-error-in-some-lua-c-code 207 | - http://stackoverflow.com/questions/13400660/binding-lua-in-static-library-segfault?rq=1 208 | - http://nticformation.com/solutions_problems.php?tuto=59091&subCategory=c+lua+jni+luajit&Category=C+Language 209 | 210 | Based on the last of the above links, I think the issue is that ```-pagezero_size 10000 -image_base 100000000``` is not included when compiling the JNI stuff. The problem is that when it is included, the compiler says 211 | >-pagezero_size option can only be used when linking a main executable 212 | which means those params can't be used for shared libraries (which JNI needs). 213 | 214 | I've confirmed that the above is the problem via [a thread](http://www.freelists.org/post/luajit/luaL-newstate-fails-on-64bit-Mac-cant-set-linker-flags) involving Lua's maintainer, Mike Pall. This is specifically an issue on 64-bit macOS. If I compile a 32-bit LuaJIT from source, then I should be able to get things to work. But, a 32-bit version might not be as useful for our purposes. To build the 32-bit LuaJIT binary, you can run the following commands inside the LuaJIT directory: 215 | 216 | ```CFLAGS="-arch i386" GCCFLAGS="-arch i386" LDFLAGS="-arch i386" make && sudo make install``` 217 | 218 | ### Configuring Lua State 219 | 220 | Let's say that you want to set a variable to a constant and then use that constant multiple times in a calculation. One way to do this in Lua is to set a global variable and then refer to that global by name in later calculations. A simple example of this is in the directory ```config-example```. It computes the factorial of a number and then computes the sum of integers from some ```m``` up to that number. 221 | 222 | The Lua code uses the earlier factorial function and adds a sum function. This time, you'll notice that the sum references a variable ```N```. We'll set that variable from Java. 223 | 224 | ``` 225 | function factorial(n) 226 | local result = 1 227 | for i = 1, n do 228 | result = result * i 229 | end 230 | return result 231 | end 232 | 233 | -- computes $\sum_{i=m}^N i$ 234 | function sum(m) 235 | local result = 0 236 | for i = m, N do 237 | result = result + i 238 | end 239 | return result 240 | end 241 | ``` 242 | 243 | The Java code is shown below. Notice that the constructor has methods that start and close Lua. 244 | ``` 245 | 246 | import java.lang.Throwable; 247 | 248 | public class ComputationJNI 249 | { 250 | private native int sum(int m); 251 | private native String factorial(int n); 252 | private native void startLua(); 253 | private native void closeLua(); 254 | 255 | public ComputationJNI() 256 | { 257 | this.startLua(); 258 | } 259 | 260 | @Override 261 | protected void finalize() throws Throwable 262 | { 263 | this.closeLua(); 264 | } 265 | 266 | public static void main(String[] args) 267 | { 268 | System.load(args[0]); 269 | int n = Integer.valueOf(args[1]); 270 | 271 | ComputationJNI jni = new ComputationJNI(); 272 | String fact = jni.factorial(n); 273 | System.out.println(n + "! = " + fact + "\n"); 274 | int sum = -1; 275 | 276 | for (int m = 0; m < 10; m++) 277 | { 278 | sum = jni.sum(m); 279 | System.out.println("Sum(" + m + ", " + fact + ") = " + sum); 280 | } 281 | } 282 | } 283 | ``` 284 | 285 | The JNI code has functions for starting and closing Lua, which are nice to have on the Java side when instantiating and garbage-collecting JNI instances. 286 | ``` 287 | #include 288 | #include 289 | #include "ComputationJNI.h" 290 | #include 291 | #include 292 | #include 293 | #include 294 | #include 295 | #include 296 | #include 297 | #include 298 | 299 | lua_State *L; 300 | 301 | 302 | JNIEXPORT void JNICALL Java_ComputationJNI_startLua(JNIEnv *env, jobject thisObj) 303 | { 304 | L = luaL_newstate(); 305 | 306 | if (!L) 307 | { 308 | fprintf(stderr, "%s\n", "Cannot create new Lua state!"); 309 | exit(-1); 310 | } 311 | luaL_openlibs(L); 312 | } 313 | 314 | 315 | JNIEXPORT void JNICALL Java_ComputationJNI_closeLua(JNIEnv *env, jobject thisObj) 316 | { 317 | lua_close(L); 318 | } 319 | 320 | 321 | JNIEXPORT jstring JNICALL Java_ComputationJNI_factorial(JNIEnv *env, jobject thisObj, jint n) 322 | { 323 | // load factorial function from script onto stack 324 | luaL_loadfile(L, "computation.lua"); 325 | lua_pcall(L, 0, 0, 0); 326 | lua_getglobal(L, "factorial"); 327 | 328 | lua_pushnumber(L, (int)n); // push parameter onto stack 329 | 330 | if (lua_pcall(L, 1, 1, 0) != 0) 331 | { 332 | fprintf(stderr, "%s\n", lua_tostring(L, -1)); 333 | luaT_stackdump(L); 334 | exit(-1); 335 | } 336 | 337 | // pop output off stack and store as a global variable 338 | lua_setglobal(L, "N"); 339 | 340 | jstring result = (*env)->NewStringUTF(env, "N"); // pass global var name to Java 341 | printf("Lua global var: %s", "N"); 342 | return result; 343 | } 344 | 345 | 346 | JNIEXPORT jint JNICALL Java_ComputationJNI_sum(JNIEnv *env, jobject thisObj, jint m) 347 | { 348 | // convert name of global var holding function input to C string 349 | // const char *var_name = (*env)->GetStringUTFChars(env, n, NULL); 350 | // fprintf(stderr, "Global name: %s", var_name); 351 | 352 | // load factorial function from script onto stack 353 | luaL_loadfile(L, "computation.lua"); 354 | lua_pcall(L, 0, 0, 0); 355 | lua_getglobal(L, "sum"); 356 | lua_pushnumber(L, (int)m); 357 | 358 | if (lua_pcall(L, 1, 1, 0) != 0) 359 | { 360 | fprintf(stderr, "%s\n", lua_tostring(L, -1)); 361 | luaT_stackdump(L); 362 | return 1; 363 | } 364 | 365 | // convert result to Java int 366 | jint result = (jint)lua_tonumber(L, -1); 367 | lua_pop(L, 1); // remove from stack 368 | 369 | // (*env)->ReleaseStringUTFChars(env, n, var_name); // release mem from C string 370 | return result; // return int to Java 371 | } 372 | ``` 373 | 374 | ### Returning Function References 375 | 376 | Above, we stored a value in a global variable so that we could use it again. That would be find for storing a constant, such as Avogadro's number. But what if you want to call a function multiple times? Is a global variable the best way to go? Probably not. Lua lets you create a reference to a function. Lua's C API has a function ```luaL_ref``` that will store the value on top of the stack in the registry and return an integer that refers to the value in the registry. So, you can load the function onto the stack, call ```lua_ref``` to store it in the registry, and then use ```lua_rawgeti``` to push the function onto the stack again. See the example in the ```function-ref-example``` directory. Build with the ```make``` and run with ```java LuaJNI ```. 377 | 378 | 379 | 380 | --------------------------------------------------------------------------------