You can build "foreign-jextract" branch of panama repo https://github.com/openjdk/panama-foreign
Using foreign function call in Java involves the following two steps:
import static org.hello.helloworld_h.*;
public class HelloWorld {
public static void main(String[] args) {
helloworld();
}
}
jextract -l python2.7 \
-I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include \
-I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/python2.7/ \
-t org.python \
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/python2.7/Python.h
import org.python.Cstring;
import static jdk.incubator.foreign.MemoryAddress.NULL;
// import jextracted python 'header' class
import static org.python.RuntimeHelper.*;
import static org.python.Python_h.*;
public class PythonMain {
public static void main(String[] args) {
String script = "print(sum([33, 55, 66])); print('Hello from Python!')\n";
Py_Initialize();
try (var s = Cstring.toCString(script)) {
var str = s.baseAddress();
PyRun_SimpleStringFlags(str, NULL);
Py_Finalize();
}
}
}
java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign \
-Djava.library.path=/System/Library/Frameworks/Python.framework/Versions/2.7/lib \
PythonMain.java
jextract -l readline -t org.unix \
-I /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include \
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/readline/readline.h
import org.unix.Cstring;
import static org.unix.RuntimeHelper.*;
import static org.unix.readline_h.*;
public class Readline {
public static void main(String[] args) {
try (var s = Cstring.toCString("name? ")) {
var pstr = s.baseAddress();
// call "readline" API
var p = readline(pstr);
// print char* as is
System.out.println(p);
// convert char* ptr from readline as Java String & print it
System.out.println("Hello, " + Cstring.toJavaString(p));
}
}
}
java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign \
-Djava.library.path=/usr/local/opt/readline/lib/ Readline.java
jextract -t org.unix -lcurl \
-I /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/ \
-I /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/curl/ \
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/curl/curl.h
import org.unix.Cstring;
import static jdk.incubator.foreign.MemoryAddress.NULL;
import static org.unix.RuntimeHelper.*;
import static org.unix.curl_h.*;
public class CurlMain {
public static void main(String[] args) {
var urlStr = args[0];
curl_global_init(CURL_GLOBAL_DEFAULT());
var curl = curl_easy_init();
if(!curl.equals(NULL)) {
try (var s = Cstring.toCString(urlStr)) {
var url = s.baseAddress();
curl_easy_setopt(curl, CURLOPT_URL(), url);
int res = curl_easy_perform(curl);
if (res != CURLE_OK()) {
curl_easy_cleanup(curl);
}
}
}
curl_global_cleanup();
}
}
# run this shell script by passing a URL as first argument
java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign \
-Djava.library.path=/usr/lib CurlMain.java $*
BLAS is a popular library that allows fast matrix and vector computation: http://www.netlib.org/blas/.
On Mac, blas is available as part of the OpenBLAS library: https://github.com/xianyi/OpenBLAS/wiki
OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version.
You can install openblas using HomeBrew
It installs include and lib directories under /usr/local/opt/openblas
The following command can be used to extract cblas.h on MacOs
jextract -C "-D FORCE_OPENBLAS_COMPLEX_STRUCT" \
-I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include \
-l openblas -t blas /usr/local/opt/openblas/include/cblas.h
import jdk.incubator.foreign.NativeAllocationScope;
import blas.*;
import static blas.RuntimeHelper.*;
import static blas.cblas_h.*;
public class TestBlas {
public static void main(String[] args) {
int Layout;
int transa;
double alpha, beta;
int m, n, lda, incx, incy, i;
Layout = CblasColMajor();
transa = CblasNoTrans();
m = 4; /* Size of Column ( the number of rows ) */
n = 4; /* Size of Row ( the number of columns ) */
lda = 4; /* Leading dimension of 5 * 4 matrix is 5 */
incx = 1;
incy = 1;
alpha = 1;
beta = 0;
try (NativeAllocationScope scope = NativeAllocationScope.unboundedScope()) {
var a = Cdouble.allocateArray(m*n, scope);
var x = Cdouble.allocateArray(n, scope);
var y = Cdouble.allocateArray(n, scope);
/* The elements of the first column */
Cdouble.set(a, 0, 1.0);
Cdouble.set(a, 1, 2.0);
Cdouble.set(a, 2, 3.0);
Cdouble.set(a, 3, 4.0);
/* The elements of the second column */
Cdouble.set(a, m, 1.0);
Cdouble.set(a, m + 1, 1.0);
Cdouble.set(a, m + 2, 1.0);
Cdouble.set(a, m + 3, 1.0);
/* The elements of the third column */
Cdouble.set(a, m*2, 3.0);
Cdouble.set(a, m*2 + 1, 4.0);
Cdouble.set(a, m*2 + 2, 5.0);
Cdouble.set(a, m*2 + 3, 6.0);
/* The elements of the fourth column */
Cdouble.set(a, m*3, 5.0);
Cdouble.set(a, m*3 + 1, 6.0);
Cdouble.set(a, m*3 + 2, 7.0);
Cdouble.set(a, m*3 + 3, 8.0);
/* The elemetns of x and y */
Cdouble.set(x, 0, 1.0);
Cdouble.set(x, 1, 2.0);
Cdouble.set(x, 2, 1.0);
Cdouble.set(x, 3, 1.0);
Cdouble.set(y, 0, 0.0);
Cdouble.set(y, 1, 0.0);
Cdouble.set(y, 2, 0.0);
Cdouble.set(y, 3, 0.0);
cblas_dgemv(Layout, transa, m, n, alpha, a, lda, x, incx, beta, y, incy);
/* Print y */
for (i = 0; i < n; i++) {
System.out.print(String.format(" y%d = %f\n", i, Cdouble.get(y, (long)i)));
}
}
}
}
java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign \
-Djava.library.path=/usr/local/opt/openblas/lib \
TestBlas.java
On Mac OS, lapack is installed under /usr/local/opt/lapack directory.
jextract \
-I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include \
-l lapacke -t lapack \
--filter lapacke.h \
/usr/local/opt/lapack/include/lapacke.h
import jdk.incubator.foreign.NativeAllocationScope;
import lapack.*;
import static lapack.lapacke_h.*;
public class TestLapack {
public static void main(String[] args) {
/* Locals */
try (var scope = NativeAllocationScope.unboundedScope()) {
var A = Cdouble.allocateArray(new double[]{
1, 2, 3, 4, 5, 1, 3, 5, 2, 4, 1, 4, 2, 5, 3
}, scope);
var b = Cdouble.allocateArray(new double[]{
-10, 12, 14, 16, 18, -3, 14, 12, 16, 16
}, scope);
int info, m, n, lda, ldb, nrhs;
/* Initialization */
m = 5;
n = 3;
nrhs = 2;
lda = 5;
ldb = 5;
/* Print Entry Matrix */
print_matrix_colmajor("Entry Matrix A", m, n, A, lda );
/* Print Right Rand Side */
print_matrix_colmajor("Right Hand Side b", n, nrhs, b, ldb );
System.out.println();
/* Executable statements */
// printf( "LAPACKE_dgels (col-major, high-level) Example Program Results\n" );
/* Solve least squares problem*/
info = LAPACKE_dgels(LAPACK_COL_MAJOR(), (byte)'N', m, n, nrhs, A, lda, b, ldb);
/* Print Solution */
print_matrix_colmajor("Solution", n, nrhs, b, ldb );
System.out.println();
System.exit(info);
}
}
static void print_matrix_colmajor(String msg, int m, int n, MemoryAddress mat, int ldm) {
int i, j;
System.out.printf("\n %s\n", msg);
for( i = 0; i < m; i++ ) {
for( j = 0; j < n; j++ ) System.out.printf(" %6.2f", Cdouble.get(mat, i+j*ldm));
System.out.printf( "\n" );
}
}
}
java -Dforeign.restricted=permit \
--add-modules jdk.incubator.foreign \
-Djava.library.path=/usr/local/opt/lapack/lib \
TestLapack.java
jextract -t org.unix \
-I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include \
--filter libproc.h \
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/libproc.h
import jdk.incubator.foreign.NativeAllocationScope;
import org.unix.*;
import static jdk.incubator.foreign.MemoryAddress.NULL;
import static org.unix.libproc_h.*;
public class LibprocMain {
private static final int NAME_BUF_MAX = 256;
public static void main(String[] args) {
try (var scope = NativeAllocationScope.unboundedScope()) {
// get the number of processes
int numPids = proc_listallpids(NULL, 0);
// allocate an array
var pids = Cint.allocateArray(numPids, scope);
// list all the pids into the native array
proc_listallpids(pids, numPids);
// convert native array to java array
int[] jpids = Cint.toJavaArray(pids.segment());
// buffer for process name
var nameBuf = Cchar.allocateArray(NAME_BUF_MAX,scope);
for (int i = 0; i < jpids.length; i++) {
int pid = jpids[i];
// get the process name
proc_name(pid, nameBuf, NAME_BUF_MAX);
String procName = Cstring.toJavaString(nameBuf);
// print pid and process name
System.out.printf("%d %s\n", pid, procName);
}
}
}
}
java -Dforeign.restricted=permit \
--add-modules jdk.incubator.foreign \
-Djava.library.path=/usr/lib LibprocMain.java
jextract -t com.github -lgit2 \
-I /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/ \
-I ${LIBGIT2_HOME}/include/ \
-I ${LIBGIT2_HOME}/include/git2 \
${LIBGIT2_HOME}/include/git2.h
import static com.github.git2_h.*;
import static jdk.incubator.foreign.CSupport.*;
import static jdk.incubator.foreign.MemoryAddress.NULL;
import static jdk.incubator.foreign.NativeAllocationScope.*;
import static com.github.Cstring.*;
public class GitClone {
public static void main(String[] args) {
if (args.length != 2) {
System.err.println("java GitClone <url> <path>");
System.exit(1);
}
git_libgit2_init();
try (var scope = unboundedScope()) {
var repo = scope.allocate(C_POINTER, NULL);
var url = toCString(args[0], scope);
var path = toCString(args[1], scope);
System.out.println(git_clone(repo, url, path, NULL));
}
git_libgit2_shutdown();
}
}
# file run.sh
java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign \
-Djava.library.path=${LIBGIT2_HOME}/build/ \
GitClone.java $*
jextract \
-I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include \
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sqlite3.h \
-t org.sqlite -lsqlite3
import org.sqlite.Cpointer;
import org.sqlite.Cstring;
import org.sqlite.RuntimeHelper.CScope;
import static jdk.incubator.foreign.MemoryAddress.NULL;
import static org.sqlite.sqlite3_h.*;
public class SqliteMain {
public static void main(String[] args) throws Exception {
try (var scope = new CScope()) {
// char** errMsgPtrPtr;
var errMsgPtrPtr = Cpointer.allocate(NULL, scope);
// sqlite3** dbPtrPtr;
var dbPtrPtr = Cpointer.allocate(NULL, scope);
int rc = sqlite3_open(Cstring.toCString("employee.db",scope), dbPtrPtr);
if (rc != 0) {
System.err.println("sqlite3_open failed: " + rc);
return;
} else {
System.out.println("employee db opened");
}
// sqlite3* dbPtr;
var dbPtr = Cpointer.get(dbPtrPtr);
// create a new table
var sql = Cstring.toCString(
"CREATE TABLE EMPLOYEE (" +
" ID INT PRIMARY KEY NOT NULL," +
" NAME TEXT NOT NULL," +
" SALARY REAL NOT NULL )", scope);
rc = sqlite3_exec(dbPtr, sql, NULL, NULL, errMsgPtrPtr);
if (rc != 0) {
System.err.println("sqlite3_exec failed: " + rc);
System.err.println("SQL error: " + Cstring.toJavaString(Cpointer.get(errMsgPtrPtr)));
sqlite3_free(Cpointer.get(errMsgPtrPtr));
} else {
System.out.println("employee table created");
}
// insert two rows
sql = Cstring.toCString(
"INSERT INTO EMPLOYEE (ID,NAME,SALARY) " +
"VALUES (134, 'Xyz', 200000.0); " +
"INSERT INTO EMPLOYEE (ID,NAME,SALARY) " +
"VALUES (333, 'Abc', 100000.0);", scope
);
rc = sqlite3_exec(dbPtr, sql, NULL, NULL, errMsgPtrPtr);
if (rc != 0) {
System.err.println("sqlite3_exec failed: " + rc);
System.err.println("SQL error: " + Cstring.toJavaString(Cpointer.get(errMsgPtrPtr)));
sqlite3_free(Cpointer.get(errMsgPtrPtr));
} else {
System.out.println("rows inserted");
}
int[] rowNum = new int[1];
// callback to print rows from SELECT query
var callback = sqlite3_exec$callback.allocate((a, argc, argv, columnNames) -> {
System.out.println("Row num: " + rowNum[0]++);
System.out.println("numColumns = " + argc);
argv = Cpointer.asArray(argv, argc);
columnNames = Cpointer.asArray(columnNames, argc);
for (int i = 0; i < argc; i++) {
String name = Cstring.toJavaString(Cpointer.get(columnNames, i));
String value = Cstring.toJavaString(Cpointer.get(argv, i));
System.out.printf("%s = %s\n", name, value);
}
return 0;
});
scope.register(callback);
// select query
sql = Cstring.toCString("SELECT * FROM EMPLOYEE", scope);
rc = sqlite3_exec(dbPtr, sql, callback.baseAddress(), NULL, errMsgPtrPtr);
if (rc != 0) {
System.err.println("sqlite3_exec failed: " + rc);
System.err.println("SQL error: " + Cstring.toJavaString(Cpointer.get(errMsgPtrPtr)));
sqlite3_free(Cpointer.get(errMsgPtrPtr));
} else {
System.out.println("done");
}
sqlite3_close(dbPtr);
}
}
}