1 % Using Panama "foreign" JDK
  2 
  3 <?xml version="1.0" encoding="utf-8"?>
  4 
  5 # Using Panama "foreign-jextract" JDK
  6 
  7 You can build "foreign-jextract" branch of panama repo [https://github.com/openjdk/panama-foreign](https://github.com/openjdk/panama-foreign)
  8 
  9 Using foreign function call in Java involves the following two steps:
 10 
 11 1. Use **jextract** tool to generate java interface for your C header file(s)
 12 2. Invoke C functions via the jextracted Java interface
 13 
 14 ## Hello World
 15 
 16 ### Hello World C Header (helloworld.h)
 17 
 18 ```C
 19 
 20 #ifndef helloworld_h
 21 #define helloworld_h
 22 
 23 extern void helloworld(void);
 24 
 25 #endif /* helloworld_h */
 26 
 27 
 28 ```
 29 
 30 ### Hello World C Source (helloworld.c)
 31 
 32 ```C
 33 
 34 #include <stdio.h>
 35 
 36 #include "helloworld.h"
 37 
 38 void helloworld(void) {
 39     printf("Hello World!\n");
 40 }
 41 
 42 ```
 43 
 44 ### Building Hello World
 45 
 46 ```sh
 47 
 48 cc -shared -o libhelloworld.dylib helloworld.c
 49 
 50 ```
 51 
 52 
 53 ### jextract a Jar file for helloworld.h
 54 
 55 ```sh
 56 
 57 jextract -t org.hello -lhelloworld helloworld.h
 58 
 59 ```
 60 
 61 ### Java program that uses extracted helloworld interface
 62 
 63 ```java
 64 
 65 import static org.hello.helloworld_h.*;
 66 
 67 public class HelloWorld {
 68     public static void main(String[] args) {
 69         helloworld();
 70     }
 71 }
 72 
 73 ```
 74 
 75 ### Running the Java code that invokes helloworld
 76 
 77 ```sh
 78 
 79 java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign HelloWorld.java
 80 
 81 ```
 82 
 83 ## Embedding Python interpreter in your Java program (Mac OS)
 84 
 85 ### jextract Python.h
 86 
 87 ```sh
 88 
 89 jextract -l python2.7 \
 90   -I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include \
 91   -I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/python2.7/ \
 92   -t org.python \
 93    /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/python2.7/Python.h
 94 
 95 ```
 96 
 97 ### Java program that uses extracted Python interface
 98 
 99 ```java
100 
101 import org.python.Cstring;
102 import static jdk.incubator.foreign.MemoryAddress.NULL;
103 // import jextracted python 'header' class
104 import static org.python.RuntimeHelper.*;
105 import static org.python.Python_h.*;
106 
107 public class PythonMain {
108     public static void main(String[] args) {
109         String script = "print(sum([33, 55, 66])); print('Hello from Python!')\n";
110 
111         Py_Initialize();
112         try (var s = Cstring.toCString(script)) {
113             var str = s.baseAddress();
114             PyRun_SimpleStringFlags(str, NULL);
115             Py_Finalize();
116         }
117     }
118 }
119 
120 ```
121 
122 ### Running the Java code that calls Python interpreter
123 
124 ```sh
125 
126 java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign \
127     -Djava.library.path=/System/Library/Frameworks/Python.framework/Versions/2.7/lib \
128     PythonMain.java
129 
130 ```
131 
132 ## Using readline library from Java code (Mac OS)
133 
134 ### jextract readline.h
135 
136 ```sh
137 
138 jextract -l readline -t org.unix \
139   -I /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include \
140    /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/readline/readline.h
141 
142 ```
143 
144 ### Java code that uses readline
145 
146 ```java
147 
148 import org.unix.Cstring;
149 import static org.unix.RuntimeHelper.*;
150 import static org.unix.readline_h.*;
151 
152 public class Readline {
153     public static void main(String[] args) {
154         try (var s = Cstring.toCString("name? ")) {
155             var pstr = s.baseAddress();
156             // call "readline" API
157             var p = readline(pstr);
158 
159             // print char* as is
160             System.out.println(p);
161             // convert char* ptr from readline as Java String & print it
162             System.out.println("Hello, " + Cstring.toJavaString(p));
163         }
164     }
165 }
166 
167 ```
168 
169 ### Running the java code that uses readline
170 
171 ```
172 java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign \
173     -Djava.library.path=/usr/local/opt/readline/lib/ Readline.java
174 
175 ```
176 
177 ## Using libcurl from Java (Mac OS)
178 
179 ### jextract curl.h
180 
181 ```sh
182 
183 jextract -t org.unix -lcurl \
184   -I /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/ \
185   -I /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/curl/ \
186   /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/curl/curl.h
187 
188 ```
189 
190 ### Java code that uses libcurl
191 
192 ```java
193 
194 import org.unix.Cstring;
195 import static jdk.incubator.foreign.MemoryAddress.NULL;
196 import static org.unix.RuntimeHelper.*;
197 import static org.unix.curl_h.*;
198 
199 public class CurlMain {
200    public static void main(String[] args) {
201        var urlStr = args[0];
202        curl_global_init(CURL_GLOBAL_DEFAULT());
203        var curl = curl_easy_init();
204        if(!curl.equals(NULL)) {
205            try (var s = Cstring.toCString(urlStr)) {
206                var url = s.baseAddress();
207                curl_easy_setopt(curl, CURLOPT_URL(), url);
208                int res = curl_easy_perform(curl);
209                if (res != CURLE_OK()) {
210                    curl_easy_cleanup(curl);
211                }
212            }
213        }
214        curl_global_cleanup();
215    }
216 }
217 
218 ```
219 
220 ### Running the java code that uses libcurl
221 
222 ```sh
223 
224 # run this shell script by passing a URL as first argument
225 java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign \
226     -Djava.library.path=/usr/lib CurlMain.java $*
227 
228 ```
229 
230 ## Using BLAS library
231 
232 BLAS is a popular library that allows fast matrix and vector computation: [http://www.netlib.org/blas/](http://www.netlib.org/blas/).
233 
234 ### Installing OpenBLAS (Mac OS)
235 
236 On Mac, blas is available as part of the OpenBLAS library: [https://github.com/xianyi/OpenBLAS/wiki](https://github.com/xianyi/OpenBLAS/wiki)
237 
238 OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version.
239 
240 You can install openblas using HomeBrew
241 
242 ```sh
243 
244 brew install openblas
245 
246 ```
247 
248 It installs include and lib directories under /usr/local/opt/openblas
249 
250 ### jextracting cblas.h (MacOS)
251 
252 The following command can be used to extract cblas.h on MacOs
253 
254 ```sh
255 
256 jextract -C "-D FORCE_OPENBLAS_COMPLEX_STRUCT" \
257   -I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include \
258   -l openblas -t blas /usr/local/opt/openblas/include/cblas.h
259 
260 ```
261 
262 ### Java sample code that uses cblas library
263 
264 ```java
265 
266 import jdk.incubator.foreign.NativeAllocationScope;
267 import blas.*;
268 import static blas.RuntimeHelper.*;
269 import static blas.cblas_h.*;
270 
271 public class TestBlas {
272     public static void main(String[] args) {
273         int Layout;
274         int transa;
275 
276         double alpha, beta;
277         int m, n, lda, incx, incy, i;
278 
279         Layout = CblasColMajor();
280         transa = CblasNoTrans();
281 
282         m = 4; /* Size of Column ( the number of rows ) */
283         n = 4; /* Size of Row ( the number of columns ) */
284         lda = 4; /* Leading dimension of 5 * 4 matrix is 5 */
285         incx = 1;
286         incy = 1;
287         alpha = 1;
288         beta = 0;
289         try (NativeAllocationScope scope = NativeAllocationScope.unboundedScope()) {
290             var a = Cdouble.allocateArray(m*n, scope);
291             var x = Cdouble.allocateArray(n, scope);
292             var y = Cdouble.allocateArray(n, scope);
293 
294             /* The elements of the first column */
295             Cdouble.set(a, 0, 1.0);
296             Cdouble.set(a, 1, 2.0);
297             Cdouble.set(a, 2, 3.0);
298             Cdouble.set(a, 3, 4.0);
299             /* The elements of the second column */
300             Cdouble.set(a, m, 1.0);
301             Cdouble.set(a, m + 1, 1.0);
302             Cdouble.set(a, m + 2, 1.0);
303             Cdouble.set(a, m + 3, 1.0);
304             /* The elements of the third column */
305             Cdouble.set(a, m*2, 3.0);
306             Cdouble.set(a, m*2 + 1, 4.0);
307             Cdouble.set(a, m*2 + 2, 5.0);
308             Cdouble.set(a, m*2 + 3, 6.0);
309             /* The elements of the fourth column */
310             Cdouble.set(a, m*3, 5.0);
311             Cdouble.set(a, m*3 + 1, 6.0);
312             Cdouble.set(a, m*3 + 2, 7.0);
313             Cdouble.set(a, m*3 + 3, 8.0);
314             /* The elemetns of x and y */
315             Cdouble.set(x, 0, 1.0);
316             Cdouble.set(x, 1, 2.0);
317             Cdouble.set(x, 2, 1.0);
318             Cdouble.set(x, 3, 1.0);
319             Cdouble.set(y, 0, 0.0);
320             Cdouble.set(y, 1, 0.0);
321             Cdouble.set(y, 2, 0.0);
322             Cdouble.set(y, 3, 0.0);
323             cblas_dgemv(Layout, transa, m, n, alpha, a, lda, x, incx, beta, y, incy);
324             /* Print y */
325             for (i = 0; i < n; i++) {
326                 System.out.print(String.format(" y%d = %f\n", i, Cdouble.get(y, (long)i)));
327             }
328         }
329     }
330 }
331 
332 ```
333 
334 ### Compiling and running the above BLAS sample
335 
336 ```sh
337 
338 java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign \
339     -Djava.library.path=/usr/local/opt/openblas/lib \
340     TestBlas.java
341 
342 ```
343 
344 ## Using LAPACK library (Mac OS)
345 
346 On Mac OS, lapack is installed under /usr/local/opt/lapack directory.
347 
348 ### jextracting lapacke.h
349 
350 ```sh
351 
352 jextract \
353    -I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include \
354    -l lapacke -t lapack \
355    --filter lapacke.h \
356    /usr/local/opt/lapack/include/lapacke.h
357 
358 ```
359 
360 ### Java sample code that uses LAPACK library
361 
362 ```java
363 
364 import jdk.incubator.foreign.NativeAllocationScope;
365 import lapack.*;
366 import static lapack.lapacke_h.*;
367 
368 public class TestLapack {
369     public static void main(String[] args) {
370 
371         /* Locals */
372         try (var scope = NativeAllocationScope.unboundedScope()) {
373             var A = Cdouble.allocateArray(new double[]{
374                     1, 2, 3, 4, 5, 1, 3, 5, 2, 4, 1, 4, 2, 5, 3
375             }, scope);
376             var b = Cdouble.allocateArray(new double[]{
377                     -10, 12, 14, 16, 18, -3, 14, 12, 16, 16
378             }, scope);
379             int info, m, n, lda, ldb, nrhs;
380 
381             /* Initialization */
382             m = 5;
383             n = 3;
384             nrhs = 2;
385             lda = 5;
386             ldb = 5;
387 
388             /* Print Entry Matrix */
389             print_matrix_colmajor("Entry Matrix A", m, n, A, lda );
390             /* Print Right Rand Side */
391             print_matrix_colmajor("Right Hand Side b", n, nrhs, b, ldb );
392             System.out.println();
393 
394             /* Executable statements */
395             //            printf( "LAPACKE_dgels (col-major, high-level) Example Program Results\n" );
396             /* Solve least squares problem*/
397             info = LAPACKE_dgels(LAPACK_COL_MAJOR(), (byte)'N', m, n, nrhs, A, lda, b, ldb);
398 
399             /* Print Solution */
400             print_matrix_colmajor("Solution", n, nrhs, b, ldb );
401             System.out.println();
402             System.exit(info);
403         }
404     }
405 
406     static void print_matrix_colmajor(String msg, int m, int n, MemoryAddress mat, int ldm) {
407         int i, j;
408         System.out.printf("\n %s\n", msg);
409 
410         for( i = 0; i < m; i++ ) {
411             for( j = 0; j < n; j++ ) System.out.printf(" %6.2f", Cdouble.get(mat, i+j*ldm));
412             System.out.printf( "\n" );
413         }
414     }
415 }
416 
417 ```
418 
419 ### Compiling and running the above LAPACK sample
420 
421 ```sh
422 
423 java -Dforeign.restricted=permit \
424     --add-modules jdk.incubator.foreign \
425     -Djava.library.path=/usr/local/opt/lapack/lib \
426     TestLapack.java
427 
428 ```
429 ## Using libproc library to list processes from Java (Mac OS)
430 
431 ### jextract libproc.h
432 
433 ```sh
434 
435 jextract -t org.unix \
436   -I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include \
437   --filter libproc.h \
438   /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/libproc.h
439 
440 ```
441 
442 ### Java program that uses libproc to list processes
443 
444 ```java
445 
446 import jdk.incubator.foreign.NativeAllocationScope;
447 import org.unix.*;
448 import static jdk.incubator.foreign.MemoryAddress.NULL;
449 import static org.unix.libproc_h.*;
450 
451 public class LibprocMain {
452     private static final int NAME_BUF_MAX = 256;
453 
454     public static void main(String[] args) {
455         try (var scope = NativeAllocationScope.unboundedScope()) {
456             // get the number of processes
457             int numPids = proc_listallpids(NULL, 0);
458             // allocate an array
459             var pids = Cint.allocateArray(numPids, scope);
460             // list all the pids into the native array
461             proc_listallpids(pids, numPids);
462             // convert native array to java array
463             int[] jpids = Cint.toJavaArray(pids.segment());
464             // buffer for process name
465             var nameBuf = Cchar.allocateArray(NAME_BUF_MAX,scope);
466             for (int i = 0; i < jpids.length; i++) {
467                 int pid = jpids[i];
468                 // get the process name
469                 proc_name(pid, nameBuf, NAME_BUF_MAX);
470                 String procName = Cstring.toJavaString(nameBuf);
471                 // print pid and process name
472                 System.out.printf("%d %s\n", pid, procName);
473             }
474         }
475     }
476 }
477 
478 ```
479 
480 ### Compiling and running the libproc sample
481 
482 ```sh
483 
484 java -Dforeign.restricted=permit \
485     --add-modules jdk.incubator.foreign \
486     -Djava.library.path=/usr/lib LibprocMain.java
487 
488 ```
489 
490 ## Using libgit2 from Java (Mac OS)
491 
492 ### Getting and building libgit2
493 
494 * Download libgit2 v1.0.0 source from https://github.com/libgit2/libgit2/releases
495 * Use cmake to build from libgit2
496 * Let ${LIBGIT2_HOME} be the directory where you expanded libgit2 sources.
497 * Let ${LIBGIT2_HOME}/build be the build directory where libgit2.dylib is built.
498 
499 ### jextract git2.h
500 
501 ```sh
502 
503 jextract -t com.github -lgit2 \
504   -I /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/ \
505   -I ${LIBGIT2_HOME}/include/ \
506   -I ${LIBGIT2_HOME}/include/git2 \
507   ${LIBGIT2_HOME}/include/git2.h
508 
509 ```
510 
511 ### Java program that uses libgit2 to clone github repo
512 
513 ```java
514 
515 import static com.github.git2_h.*;
516 import static jdk.incubator.foreign.CSupport.*;
517 import static jdk.incubator.foreign.MemoryAddress.NULL;
518 import static jdk.incubator.foreign.NativeAllocationScope.*;
519 import static com.github.Cstring.*;
520 
521 public class GitClone {
522     public static void main(String[] args) {
523           if (args.length != 2) {
524               System.err.println("java GitClone <url> <path>");
525               System.exit(1);
526           }
527           git_libgit2_init();
528           try (var scope = unboundedScope()) {
529               var repo = scope.allocate(C_POINTER, NULL);
530               var url = toCString(args[0], scope);
531               var path = toCString(args[1], scope);
532               System.out.println(git_clone(repo, url, path, NULL));
533           }
534           git_libgit2_shutdown();
535     }
536 }
537 
538 ```
539 
540 ### Compiling and running the libgit2 sample
541 
542 ```sh
543 
544 # file run.sh
545 
546 java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign \
547     -Djava.library.path=${LIBGIT2_HOME}/build/ \
548     GitClone.java $*
549 ```
550 
551 ### Cloning a github repo using the above run.sh command
552 
553 ```sh
554 
555 sh run.sh https://github.com/libgit2/libgit2.git libgit2
556 
557 ```
558 
559 ## Using sqlite3 library from Java (Mac OS)
560 
561 
562 ### jextract sqlite3.h
563 
564 ```sh
565 
566 jextract \
567   -I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include \
568   /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sqlite3.h \
569   -t org.sqlite -lsqlite3
570 
571 ```
572 ### Java program that uses sqlite3
573 
574 ```java
575 
576 import org.sqlite.Cpointer;
577 import org.sqlite.Cstring;
578 import org.sqlite.RuntimeHelper.CScope;
579 import static jdk.incubator.foreign.MemoryAddress.NULL;
580 import static org.sqlite.sqlite3_h.*;
581 
582 public class SqliteMain {
583    public static void main(String[] args) throws Exception {
584         try (var scope = new CScope()) {
585             // char** errMsgPtrPtr;
586             var errMsgPtrPtr = Cpointer.allocate(NULL, scope);
587 
588             // sqlite3** dbPtrPtr;
589             var dbPtrPtr = Cpointer.allocate(NULL, scope);
590 
591             int rc = sqlite3_open(Cstring.toCString("employee.db",scope), dbPtrPtr);
592             if (rc != 0) {
593                 System.err.println("sqlite3_open failed: " + rc);
594                 return;
595             } else {
596                 System.out.println("employee db opened");
597             }
598 
599             // sqlite3* dbPtr;
600             var dbPtr = Cpointer.get(dbPtrPtr);
601 
602             // create a new table
603             var sql = Cstring.toCString(
604                 "CREATE TABLE EMPLOYEE ("  +
605                 "  ID INT PRIMARY KEY NOT NULL," +
606                 "  NAME TEXT NOT NULL,"    +
607                 "  SALARY REAL NOT NULL )", scope);
608 
609             rc = sqlite3_exec(dbPtr, sql, NULL, NULL, errMsgPtrPtr);
610 
611             if (rc != 0) {
612                 System.err.println("sqlite3_exec failed: " + rc);
613                 System.err.println("SQL error: " + Cstring.toJavaString(Cpointer.get(errMsgPtrPtr)));
614                 sqlite3_free(Cpointer.get(errMsgPtrPtr));
615             } else {
616                 System.out.println("employee table created");
617             }
618 
619             // insert two rows
620             sql = Cstring.toCString(
621                 "INSERT INTO EMPLOYEE (ID,NAME,SALARY) " +
622                     "VALUES (134, 'Xyz', 200000.0); " +
623                 "INSERT INTO EMPLOYEE (ID,NAME,SALARY) " +
624                     "VALUES (333, 'Abc', 100000.0);", scope
625             );
626             rc = sqlite3_exec(dbPtr, sql, NULL, NULL, errMsgPtrPtr);
627 
628             if (rc != 0) {
629                 System.err.println("sqlite3_exec failed: " + rc);
630                 System.err.println("SQL error: " + Cstring.toJavaString(Cpointer.get(errMsgPtrPtr)));
631                 sqlite3_free(Cpointer.get(errMsgPtrPtr));
632             } else {
633                 System.out.println("rows inserted");
634             }
635 
636             int[] rowNum = new int[1];
637             // callback to print rows from SELECT query
638             var callback = sqlite3_exec$callback.allocate((a, argc, argv, columnNames) -> {
639                 System.out.println("Row num: " + rowNum[0]++);
640                 System.out.println("numColumns = " + argc);
641                 argv = Cpointer.asArray(argv, argc);
642                 columnNames = Cpointer.asArray(columnNames, argc);
643                 for (int i = 0; i < argc; i++) {
644                      String name = Cstring.toJavaString(Cpointer.get(columnNames, i));
645                      String value = Cstring.toJavaString(Cpointer.get(argv, i));
646                      System.out.printf("%s = %s\n", name, value);
647                 }
648                 return 0;
649             });
650             scope.register(callback);
651 
652             // select query
653             sql = Cstring.toCString("SELECT * FROM EMPLOYEE", scope);
654             rc = sqlite3_exec(dbPtr, sql, callback.baseAddress(), NULL, errMsgPtrPtr);
655 
656             if (rc != 0) {
657                 System.err.println("sqlite3_exec failed: " + rc);
658                 System.err.println("SQL error: " + Cstring.toJavaString(Cpointer.get(errMsgPtrPtr)));
659                 sqlite3_free(Cpointer.get(errMsgPtrPtr));
660             } else {
661                 System.out.println("done");
662             }
663 
664             sqlite3_close(dbPtr);
665         }
666     }
667 }
668 
669 ```
670 
671 ### Compiling and running the sqlite3 sample
672 
673 ```sh
674 
675 java -Dforeign.restricted=permit \
676    --add-modules jdk.incubator.foreign \
677    -Djava.library.path=/usr/lib SqliteMain.java
678 
679 ```