1 <?xml version="1.0" encoding="utf-8"?>
   2 
   3 # Using the `jextract` tool
   4 
   5 `jextract` is a simple - but convenient - tool which generates a Java API from one or more native C headers. The tool can be obtained by building the [foreign-jextract](https://github.com/openjdk/panama-foreign) branch of Panama foreign repository.
   6 
   7 Interacting with the `jextract` tool usually involves two steps:
   8 
   9 1. Use the `jextract` tool to generate a java interface for some C header files
  10 2. Write a Java program which invokes the wrapper API points generated by `jextract`
  11 
  12 The `jextract` tool provides some basic options in order to control how the extraction process works; these are listed below:
  13 
  14 * `-C <String>` - specify arguments to be passed to the underlying Clang parser
  15 * `-I <String>` - specify include files path
  16 * `-l <String>` - specify a library (name or full absolute path) which should be linked when the generated API is loaded
  17 * `-d <String>` - specify where to place generated files
  18 * `-t <String>`  specify the target package for the generated classes
  19 * --include-function <String> - name of function to include
  20 * --include-macro <String>    - name of constant macro to include
  21 * --include-struct <String>   - name of struct definition to include
  22 * --include-typedef <String>  - name of type definition to include
  23 * --include-union <String>    - name of union definition to include
  24 * --include-var <String>      - name of global variable to include
  25 * `--source` - generate java sources instead of classfiles
  26 
  27 The remainder of this documents shows some basic usage examples of the `jextract` tool.
  28 
  29 ## Hello World
  30 
  31 ### Hello World C Header (helloworld.h)
  32 
  33 ```C
  34 
  35 #ifndef helloworld_h
  36 #define helloworld_h
  37 
  38 extern void helloworld(void);
  39 
  40 #endif /* helloworld_h */
  41 
  42 
  43 ```
  44 
  45 ### Hello World C Source (helloworld.c)
  46 
  47 ```C
  48 
  49 #include <stdio.h>
  50 
  51 #include "helloworld.h"
  52 
  53 void helloworld(void) {
  54     printf("Hello World!\n");
  55 }
  56 
  57 ```
  58 
  59 ### Building Hello World
  60 
  61 ```sh
  62 
  63 cc -shared -o libhelloworld.dylib helloworld.c
  64 
  65 ```
  66 
  67 
  68 ### jextract a Jar file for helloworld.h
  69 
  70 ```sh
  71 
  72 jextract -t org.hello -lhelloworld helloworld.h
  73 
  74 ```
  75 
  76 ### Java program that uses extracted helloworld interface
  77 
  78 ```java
  79 
  80 import static org.hello.helloworld_h.*;
  81 
  82 public class HelloWorld {
  83     public static void main(String[] args) {
  84         helloworld();
  85     }
  86 }
  87 
  88 ```
  89 
  90 ### Running the Java code that invokes helloworld
  91 
  92 ```sh
  93 
  94 java --enable-native-access=ALL-UNNAMED --add-modules jdk.incubator.foreign HelloWorld.java
  95 
  96 ```
  97 
  98 ## Embedding Python interpreter in your Java program (Mac OS)
  99 
 100 ### jextract Python.h
 101 
 102 ```sh
 103 
 104 jextract \
 105   -l python2.7 \
 106   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include \
 107   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/python2.7/ \
 108   -t org.python \
 109    /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/python2.7/Python.h
 110 
 111 ```
 112 
 113 ### Java program that uses extracted Python interface
 114 
 115 ```java
 116 
 117 import jdk.incubator.foreign.ResourceScope;
 118 import jdk.incubator.foreign.SegmentAllocator;
 119 import static jdk.incubator.foreign.MemoryAddress.NULL;
 120 // import jextracted python 'header' class
 121 import static org.python.Python_h.*;
 122 import org.python.*;
 123 
 124 public class PythonMain {
 125     public static void main(String[] args) {
 126         String script = "print(sum([33, 55, 66])); print('Hello from Python!')\n";
 127 
 128         Py_Initialize();
 129         try (var scope = ResourceScope.newConfinedScope()) {
 130             var allocator = SegmentAllocator.nativeAllocator(scope);
 131             var str = allocator.allocateUtf8String(script);
 132             PyRun_SimpleStringFlags(str, NULL);
 133             Py_Finalize();
 134         }
 135     }
 136 }
 137 
 138 ```
 139 
 140 ### Running the Java code that calls Python interpreter
 141 
 142 ```sh
 143 
 144 java --enable-native-access=ALL-UNNAMED --add-modules jdk.incubator.foreign \
 145     -Djava.library.path=/System/Library/Frameworks/Python.framework/Versions/2.7/lib \
 146     PythonMain.java
 147 
 148 ```
 149 
 150 ## Using readline library from Java code (Mac OS)
 151 
 152 ### jextract readline.h
 153 
 154 ```sh
 155 
 156 jextract \
 157   -l readline -t org.unix \
 158   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include \
 159    /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/readline/readline.h
 160 
 161 ```
 162 
 163 ### Java code that uses readline
 164 
 165 ```java
 166 
 167 import jdk.incubator.foreign.ResourceScope;
 168 import jdk.incubator.foreign.SegmentAllocator;
 169 import static org.unix.readline_h.*;
 170 import org.unix.*;
 171 
 172 public class Readline {
 173     public static void main(String[] args) {
 174        try (var scope = ResourceScope.newConfinedScope()) {
 175             var allocator = SegmentAllocator.nativeAllocator(scope);
 176             var url = allocator.allocateUtf8String("name? ");
 177 
 178             // call "readline" API
 179             var p = readline(url);
 180 
 181             // print char* as is
 182             System.out.println(p);
 183             // convert char* ptr from readline as Java String & print it
 184             System.out.println("Hello, " + p.getUtf8String(0));
 185 
 186             // pointer returned by readline has to be 'free'd
 187             free(p);
 188         }
 189     }
 190 }
 191 
 192 ```
 193 
 194 ### Running the java code that uses readline
 195 
 196 ```
 197 java --enable-native-access=ALL-UNNAMED --add-modules jdk.incubator.foreign \
 198     -Djava.library.path=/usr/local/opt/readline/lib/ Readline.java
 199 
 200 ```
 201 
 202 ## Using libcurl from Java (Mac OS)
 203 
 204 ### jextract curl.h
 205 
 206 ```sh
 207 
 208 jextract -t org.unix -lcurl \
 209   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/ \
 210   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/curl/ \
 211   /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/curl/curl.h
 212 
 213 ```
 214 
 215 ### Java code that uses libcurl
 216 
 217 ```java
 218 
 219 import jdk.incubator.foreign.ResourceScope;
 220 import jdk.incubator.foreign.SegmentAllocator;
 221 import static jdk.incubator.foreign.MemoryAddress.NULL;
 222 import static org.jextract.curl_h.*;
 223 import org.jextract.*;
 224 
 225 public class CurlMain {
 226    public static void main(String[] args) {
 227        var urlStr = args[0];
 228        curl_global_init(CURL_GLOBAL_DEFAULT());
 229        var curl = curl_easy_init();
 230        if(!curl.equals(NULL)) {
 231            try (var scope = ResourceScope.newConfinedScope()) {
 232                var allocator = SegmentAllocator.nativeAllocator(scope);
 233                var url = allocator.allocateUtf8String(urlStr);
 234                curl_easy_setopt(curl, CURLOPT_URL(), url.address());
 235                int res = curl_easy_perform(curl);
 236                if (res != CURLE_OK()) {
 237                    String error = curl_easy_strerror(res).getUtf8String(0);
 238                    System.out.println("Curl error: " + error);
 239                    curl_easy_cleanup(curl);
 240                }
 241            }
 242        }
 243        curl_global_cleanup();
 244    }
 245 }
 246 
 247 ```
 248 
 249 ### Running the java code that uses libcurl
 250 
 251 ```sh
 252 
 253 # run this shell script by passing a URL as first argument
 254 java --enable-native-access=ALL-UNNAMED --add-modules jdk.incubator.foreign \
 255     -Djava.library.path=/usr/lib CurlMain.java $*
 256 
 257 ```
 258 
 259 ## Using BLAS library
 260 
 261 BLAS is a popular library that allows fast matrix and vector computation: [http://www.netlib.org/blas/](http://www.netlib.org/blas/).
 262 
 263 ### Installing OpenBLAS (Mac OS)
 264 
 265 On Mac, blas is available as part of the OpenBLAS library: [https://github.com/xianyi/OpenBLAS/wiki](https://github.com/xianyi/OpenBLAS/wiki)
 266 
 267 OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version.
 268 
 269 You can install openblas using HomeBrew
 270 
 271 ```sh
 272 
 273 brew install openblas
 274 
 275 ```
 276 
 277 It installs include and lib directories under /usr/local/opt/openblas
 278 
 279 ### jextracting cblas.h (MacOS)
 280 
 281 The following command can be used to extract cblas.h on MacOs
 282 
 283 ```sh
 284 
 285 jextract -C "-D FORCE_OPENBLAS_COMPLEX_STRUCT" \
 286   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include \
 287   -l openblas -t blas /usr/local/opt/openblas/include/cblas.h
 288 
 289 ```
 290 
 291 ### Java sample code that uses cblas library
 292 
 293 ```java
 294 
 295 import jdk.incubator.foreign.MemoryAddress;
 296 import jdk.incubator.foreign.SegmentAllocator;
 297 import jdk.incubator.foreign.ResourceScope;
 298 import blas.*;
 299 import static blas.cblas_h.*;
 300 
 301 public class TestBlas {
 302     public static void main(String[] args) {
 303         int Layout;
 304         int transa;
 305 
 306         double alpha, beta;
 307         int m, n, lda, incx, incy, i;
 308  
 309         Layout = CblasColMajor();
 310         transa = CblasNoTrans();
 311 
 312         m = 4; /* Size of Column ( the number of rows ) */
 313         n = 4; /* Size of Row ( the number of columns ) */
 314         lda = 4; /* Leading dimension of 5 * 4 matrix is 5 */
 315         incx = 1;
 316         incy = 1;
 317         alpha = 1;
 318         beta = 0;
 319  
 320         try (var scope = ResourceScope.newConfinedScope()) {
 321             var allocator = SegmentAllocator.newNativeArena(scope);
 322             var a = allocator.allocateArray(C_DOUBLE, new double[] {
 323                 1.0, 2.0, 3.0, 4.0,
 324                 1.0, 1.0, 1.0, 1.0,
 325                 3.0, 4.0, 5.0, 6.0,
 326                 5.0, 6.0, 7.0, 8.0
 327             });
 328             var x = allocator.allocateArray(C_DOUBLE, new double[] {
 329                 1.0, 2.0, 1.0, 1.0
 330             });
 331             var y = allocator.allocateArray(C_DOUBLE, n);
 332         
 333             cblas_dgemv(Layout, transa, m, n, alpha, a, lda, x, incx, beta, y, incy);
 334             /* Print y */
 335             for (i = 0; i < n; i++) {
 336                 System.out.print(String.format(" y%d = %f\n", i, y.getAtIndex(C_DOUBLE, i)));
 337             }
 338         }
 339     }
 340 }
 341 
 342 ```
 343 
 344 ### Compiling and running the above BLAS sample
 345 
 346 ```sh
 347 
 348 jextract \
 349   -C "-D FORCE_OPENBLAS_COMPLEX_STRUCT" \
 350   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include \
 351   -l openblas -t blas /usr/local/opt/openblas/include/cblas.h
 352 
 353 ```
 354 
 355 ## Using LAPACK library (Mac OS)
 356 
 357 On Mac OS, lapack is installed under /usr/local/opt/lapack directory.
 358 
 359 ### jextracting lapacke.h
 360 
 361 ```sh
 362 
 363 jextract \
 364    -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include \
 365    -l lapacke -t lapack \
 366    /usr/local/opt/lapack/include/lapacke.h
 367 
 368 ```
 369 
 370 ### Java sample code that uses LAPACK library
 371 
 372 ```java
 373 
 374 import jdk.incubator.foreign.MemorySegment;
 375 import jdk.incubator.foreign.SegmentAllocator;
 376 import jdk.incubator.foreign.ResourceScope;
 377 import lapack.*;
 378 import static lapack.lapacke_h.*;
 379 
 380 public class TestLapack {
 381     public static void main(String[] args) {
 382 
 383         /* Locals */
 384         try (var scope = ResourceScope.newConfinedScope()) {
 385             var allocator = SegmentAllocator.newNativeArena(scope);
 386             var A = allocator.allocateArray(C_DOUBLE, new double[]{
 387                     1, 2, 3, 4, 5, 1, 3, 5, 2, 4, 1, 4, 2, 5, 3
 388             });
 389             var b = allocator.allocateArray(C_DOUBLE, new double[]{
 390                     -10, 12, 14, 16, 18, -3, 14, 12, 16, 16
 391             });
 392             int info, m, n, lda, ldb, nrhs;
 393 
 394             /* Initialization */
 395             m = 5;
 396             n = 3;
 397             nrhs = 2;
 398             lda = 5;
 399             ldb = 5;
 400 
 401             /* Print Entry Matrix */
 402             print_matrix_colmajor("Entry Matrix A", m, n, A, lda );
 403             /* Print Right Rand Side */
 404             print_matrix_colmajor("Right Hand Side b", n, nrhs, b, ldb );
 405             System.out.println();
 406             
 407             /* Executable statements */
 408             //            printf( "LAPACKE_dgels (col-major, high-level) Example Program Results\n" );
 409             /* Solve least squares problem*/
 410             info = LAPACKE_dgels(LAPACK_COL_MAJOR(), (byte)'N', m, n, nrhs, A, lda, b, ldb);
 411  
 412             /* Print Solution */
 413             print_matrix_colmajor("Solution", n, nrhs, b, ldb );
 414             System.out.println();
 415             System.exit(info);
 416         }   
 417     }   
 418     
 419     static void print_matrix_colmajor(String msg, int m, int n, MemorySegment mat, int ldm) {
 420         int i, j;
 421         System.out.printf("\n %s\n", msg);
 422 
 423         for( i = 0; i < m; i++ ) {
 424             for( j = 0; j < n; j++ ) System.out.printf(" %6.2f", mat.getAtIndex(C_DOUBLE, i+j*ldm));
 425             System.out.printf( "\n" );
 426         }
 427     }
 428 }
 429 
 430 ```
 431 
 432 ### Compiling and running the above LAPACK sample
 433 
 434 ```sh
 435 
 436 java --enable-native-access=ALL-UNNAMED \
 437     --add-modules jdk.incubator.foreign \
 438     -Djava.library.path=/usr/local/opt/lapack/lib \
 439     TestLapack.java
 440 
 441 ```
 442 ## Using libproc library to list processes from Java (Mac OS)
 443 
 444 ### jextract libproc.h
 445 
 446 ```sh
 447 
 448 jextract \
 449   -t org.unix \
 450   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include \
 451   /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/libproc.h
 452 
 453 ```
 454 
 455 ### Java program that uses libproc to list processes
 456 
 457 ```java
 458 
 459 import jdk.incubator.foreign.MemorySegment;
 460 import jdk.incubator.foreign.ResourceScope;
 461 import jdk.incubator.foreign.SegmentAllocator;
 462 import org.unix.*;
 463 import static jdk.incubator.foreign.MemoryAddress.NULL;
 464 import static org.unix.libproc_h.*;
 465 
 466 public class LibprocMain {
 467     private static final int NAME_BUF_MAX = 256;
 468 
 469     public static void main(String[] args) {
 470         try (var scope = ResourceScope.newConfinedScope()) {
 471             var allocator = SegmentAllocator.newNativeArena(scope);
 472             // get the number of processes
 473             int numPids = proc_listallpids(NULL, 0);
 474             // allocate an array
 475             var pids = allocator.allocateArray(C_INT, numPids);
 476             // list all the pids into the native array
 477             proc_listallpids(pids, numPids);
 478             // convert native array to java array
 479             int[] jpids = pids.toArray(C_INT);
 480             // buffer for process name
 481             var nameBuf = allocator.allocateArray(C_CHAR, NAME_BUF_MAX);
 482             for (int i = 0; i < jpids.length; i++) {
 483                 int pid = jpids[i];
 484                 // get the process name
 485                 proc_name(pid, nameBuf, NAME_BUF_MAX);
 486                 String procName = nameBuf.getUtf8String(0);
 487                 // print pid and process name
 488                 System.out.printf("%d %s\n", pid, procName);
 489             }
 490         }
 491     }
 492 }
 493 
 494 ```
 495 
 496 ### Compiling and running the libproc sample
 497 
 498 ```sh
 499 
 500 java --enable-native-access=ALL-UNNAMED \
 501     --add-modules jdk.incubator.foreign \
 502     -Djava.library.path=/usr/lib LibprocMain.java
 503 
 504 ```
 505 
 506 ## Using libgit2 from Java (Mac OS)
 507 
 508 ### Getting and building libgit2
 509 
 510 * Download libgit2 v1.0.0 source from https://github.com/libgit2/libgit2/releases
 511 * Use cmake to build from libgit2
 512 * Let ${LIBGIT2_HOME} be the directory where you expanded libgit2 sources.
 513 * Let ${LIBGIT2_HOME}/build be the build directory where libgit2.dylib is built.
 514 
 515 ### jextract git2.h
 516 
 517 ```sh
 518 
 519 jextract \
 520   -t com.github -lgit2 \
 521   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/ \
 522   -I ${LIBGIT2_HOME}/include/ \
 523   -I ${LIBGIT2_HOME}/include/git2 \
 524   ${LIBGIT2_HOME}/include/git2.h
 525 
 526 ```
 527 
 528 ### Java program that uses libgit2 to clone github repo
 529 
 530 ```java
 531 
 532 import jdk.incubator.foreign.MemoryAddress;
 533 import jdk.incubator.foreign.SegmentAllocator;
 534 import jdk.incubator.foreign.ResourceScope;
 535 import static com.github.git2_h.*;
 536 import static jdk.incubator.foreign.MemoryAddress.NULL;
 537 import com.github.*;
 538 
 539 public class GitClone {
 540     public static void main(String[] args) {
 541           if (args.length != 2) {
 542               System.err.println("java GitClone <url> <path>");
 543               System.exit(1);
 544           }
 545           git_libgit2_init();
 546           try (var scope = ResourceScope.newConfinedScope()) {
 547               var allocator = SegmentAllocator.newNativeArena(scope);
 548               var repo = allocator.allocate(C_POINTER);
 549               var url = allocator.allocateUtf8String(args[0]);
 550               var path = allocator.allocateUtf8String(args[1]);
 551               System.out.println(git_clone(repo, url, path, NULL));
 552           }          
 553           git_libgit2_shutdown();
 554     }
 555 }
 556 
 557 ```
 558 
 559 ### Compiling and running the libgit2 sample
 560 
 561 ```sh
 562 
 563 # file run.sh
 564 
 565 java --enable-native-access=ALL-UNNAMED --add-modules jdk.incubator.foreign \
 566     -Djava.library.path=${LIBGIT2_HOME}/build/ \
 567     GitClone.java $*
 568 ```
 569 
 570 ### Cloning a github repo using the above run.sh command
 571 
 572 ```sh
 573 
 574 sh run.sh https://github.com/libgit2/libgit2.git libgit2
 575 
 576 ```
 577 
 578 ## Using sqlite3 library from Java (Mac OS)
 579 
 580 
 581 ### jextract sqlite3.h
 582 
 583 ```sh
 584 
 585 jextract \
 586   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include \
 587   /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sqlite3.h \
 588   -t org.sqlite -lsqlite3
 589 
 590 ```
 591 ### Java program that uses sqlite3
 592 
 593 ```java
 594 
 595 import jdk.incubator.foreign.MemoryAddress;
 596 import jdk.incubator.foreign.MemorySegment;
 597 import jdk.incubator.foreign.ResourceScope;
 598 import jdk.incubator.foreign.SegmentAllocator;
 599 import org.sqlite.*;
 600 import static jdk.incubator.foreign.MemoryAddress.NULL;
 601 import static org.sqlite.sqlite3_h.*;
 602 
 603 public class SqliteMain {
 604    public static void main(String[] args) throws Exception {
 605         try (var scope = ResourceScope.newConfinedScope()) {
 606             var allocator = SegmentAllocator.newNativeArena(scope);
 607             // char** errMsgPtrPtr;
 608             var errMsgPtrPtr = allocator.allocate(C_POINTER);
 609 
 610             // sqlite3** dbPtrPtr;
 611             var dbPtrPtr = allocator.allocate(C_POINTER);
 612 
 613             int rc = sqlite3_open(allocator.allocateUtf8String("employee.db"), dbPtrPtr);
 614             if (rc != 0) {
 615                 System.err.println("sqlite3_open failed: " + rc);
 616                 return;
 617             } else {
 618                 System.out.println("employee db opened");
 619             }
 620 
 621             // sqlite3* dbPtr;
 622             var dbPtr = dbPtrPtr.get(C_POINTER, 0);
 623 
 624             // create a new table
 625             var sql = allocator.allocateUtf8String(
 626                 "CREATE TABLE EMPLOYEE ("  +
 627                 "  ID INT PRIMARY KEY NOT NULL," +
 628                 "  NAME TEXT NOT NULL,"    +
 629                 "  SALARY REAL NOT NULL )");
 630 
 631             rc = sqlite3_exec(dbPtr, sql, NULL, NULL, errMsgPtrPtr);
 632 
 633             if (rc != 0) {
 634                 System.err.println("sqlite3_exec failed: " + rc);
 635                 System.err.println("SQL error: " + errMsgPtrPtr.get(C_POINTER, 0).getUtf8String(0));
 636                 sqlite3_free(errMsgPtrPtr.get(C_POINTER, 0));
 637             } else {
 638                 System.out.println("employee table created");
 639             }
 640 
 641             // insert two rows
 642             sql = allocator.allocateUtf8String(
 643                 "INSERT INTO EMPLOYEE (ID,NAME,SALARY) " +
 644                     "VALUES (134, 'Xyz', 200000.0); " +
 645                 "INSERT INTO EMPLOYEE (ID,NAME,SALARY) " +
 646                     "VALUES (333, 'Abc', 100000.0);"
 647             );
 648             rc = sqlite3_exec(dbPtr, sql, NULL, NULL, errMsgPtrPtr);
 649 
 650             if (rc != 0) {
 651                 System.err.println("sqlite3_exec failed: " + rc);
 652                 System.err.println("SQL error: " + errMsgPtrPtr.get(C_POINTER, 0).getUtf8String(0));
 653                 sqlite3_free(errMsgPtrPtr.get(C_POINTER, 0));
 654             } else {
 655                 System.out.println("rows inserted");
 656             }
 657 
 658             int[] rowNum = new int[1];
 659             // callback to print rows from SELECT query
 660             var callback = sqlite3_exec$callback.allocate((a, argc, argv, columnNames) -> {
 661                 System.out.println("Row num: " + rowNum[0]++);
 662                 System.out.println("numColumns = " + argc);
 663                 var argv_seg = MemorySegment.ofAddress(argv, C_POINTER.byteSize() * argc, scope);
 664                 var columnNames_seg = MemorySegment.ofAddress(columnNames, C_POINTER.byteSize() * argc, scope);
 665                 for (int i = 0; i < argc; i++) {
 666                      String name = columnNames_seg.getAtIndex(C_POINTER, i).getUtf8String(0);
 667                      String value = argv_seg.getAtIndex(C_POINTER, i).getUtf8String(0);
 668 
 669                      System.out.printf("%s = %s\n", name, value);
 670                 }
 671                 return 0;
 672             }, scope);
 673 
 674             // select query
 675             sql = allocator.allocateUtf8String("SELECT * FROM EMPLOYEE");
 676             rc = sqlite3_exec(dbPtr, sql, callback, NULL, errMsgPtrPtr);
 677 
 678             if (rc != 0) {
 679                 System.err.println("sqlite3_exec failed: " + rc);
 680                 System.err.println("SQL error: " + errMsgPtrPtr.get(C_POINTER, 0).getUtf8String(0));
 681                 sqlite3_free(errMsgPtrPtr.get(C_POINTER, 0));
 682             } else {
 683                 System.out.println("done");
 684             }
 685 
 686             sqlite3_close(dbPtr);
 687         }
 688     }
 689 }
 690 
 691 ```
 692 
 693 ### Compiling and running the sqlite3 sample
 694 
 695 ```sh
 696 
 697 java --enable-native-access=ALL-UNNAMED \
 698    --add-modules jdk.incubator.foreign \
 699    -Djava.library.path=/usr/lib SqliteMain.java
 700 
 701 ```
 702 
 703 ## Using OpenGL library from Java (Mac OS)
 704 
 705 ### jextract glut.h
 706 
 707 ```sh
 708 
 709 jextract -t opengl -lGL -l/System/Library/Frameworks/GLUT.framework/Versions/Current/GLUT \
 710   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/ \
 711   -C-F/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks \
 712   /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/GLUT.framework/Headers/glut.h
 713 
 714 ```
 715 ### Java program that uses OpenGL
 716 
 717 ```java
 718 
 719 import jdk.incubator.foreign.ResourceScope;
 720 import jdk.incubator.foreign.SegmentAllocator;
 721 import opengl.*;
 722 import static opengl.glut_h.*;
 723 
 724 public class Teapot {
 725     private float rot = 0;
 726 
 727     Teapot(SegmentAllocator allocator) {
 728         // Reset Background
 729         glClearColor(0f, 0f, 0f, 0f);
 730         // Setup Lighting
 731         glShadeModel(GL_SMOOTH());
 732         var pos = allocator.allocateArray(C_FLOAT, new float[] {0.0f, 15.0f, -15.0f, 0});
 733         glLightfv(GL_LIGHT0(), GL_POSITION(), pos);
 734         var spec = allocator.allocateArray(C_FLOAT, new float[] {1, 1, 1, 0});
 735         glLightfv(GL_LIGHT0(), GL_AMBIENT(), spec);
 736         glLightfv(GL_LIGHT0(), GL_DIFFUSE(), spec);
 737         glLightfv(GL_LIGHT0(), GL_SPECULAR(), spec);
 738         var shini = allocator.allocate(C_FLOAT, 113);
 739         glMaterialfv(GL_FRONT(), GL_SHININESS(), shini);
 740         glEnable(GL_LIGHTING());
 741         glEnable(GL_LIGHT0());
 742         glEnable(GL_DEPTH_TEST());
 743     }
 744 
 745     void display() {
 746         glClear(GL_COLOR_BUFFER_BIT() | GL_DEPTH_BUFFER_BIT());
 747         glPushMatrix();
 748         glRotatef(-20f, 1f, 1f, 0f);
 749         glRotatef(rot, 0f, 1f, 0f);
 750         glutSolidTeapot(0.5d);
 751         glPopMatrix();
 752         glutSwapBuffers();
 753     }
 754 
 755     void onIdle() {
 756         rot += 0.1;
 757         glutPostRedisplay();
 758     }
 759 
 760     public static void main(String[] args) {
 761         try (var scope = ResourceScope.newConfinedScope()) {
 762             var allocator = SegmentAllocator.newNativeArena(scope);
 763             var argc = allocator.allocate(C_INT, 0);
 764             glutInit(argc, argc);
 765             glutInitDisplayMode(GLUT_DOUBLE() | GLUT_RGB() | GLUT_DEPTH());
 766             glutInitWindowSize(500, 500);
 767             glutCreateWindow(allocator.allocateUtf8String("Hello Panama!"));
 768             var teapot = new Teapot(allocator);
 769             var displayStub = glutDisplayFunc$func.allocate(teapot::display, scope);
 770             var idleStub = glutIdleFunc$func.allocate(teapot::onIdle, scope);
 771             glutDisplayFunc(displayStub);
 772             glutIdleFunc(idleStub);
 773             glutMainLoop();
 774         }
 775     }
 776 }
 777 
 778 ```
 779 
 780 ### Compiling and running the OpenGL sample
 781 
 782 ```sh
 783 
 784 java -XstartOnFirstThread --enable-native-access=ALL-UNNAMED --add-modules jdk.incubator.foreign \
 785     -Djava.library.path=.:/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries/ Teapot.java $*
 786 
 787 ```
 788 
 789 ## Using tensorflow (Mac OS)
 790 
 791 ### getting libtensorflow
 792 
 793 * Download tensorflow library from
 794 
 795     https://www.tensorflow.org/install/lang_c
 796 
 797 * extract the downloaded tar in a directory called LIBTENSORFLOW_HOME
 798 
 799 ###  jextract c_api.h
 800 
 801 ```sh
 802 
 803 jextract --source \
 804   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/ \
 805   -t org.tensorflow \
 806   -I ${LIBTENSORFLOW_HOME}/include \
 807   -l ${LIBTENSORFLOW_HOME}/lib/libtensorflow.dylib \
 808   ${LIBTENSORFLOW_HOME}/include/tensorflow/c/c_api.h
 809 
 810 javac --add-modules jdk.incubator.foreign org/tensorflow/*.java
 811 
 812 ```
 813 
 814 ### Python program that creates and saves model
 815 
 816 The following Python program should be run to create and save model
 817 which will read and printed by a Java program.
 818 
 819 Note: you need to install tensorflow package to run this python script.
 820 
 821 ```python
 822 
 823 import tensorflow as tf
 824 from tensorflow.keras import models, layers
 825 from tensorflow.keras.datasets import mnist
 826 
 827 model = tf.keras.models.Sequential([
 828   tf.keras.layers.Flatten(input_shape=(28, 28)),
 829   tf.keras.layers.Dense(128,activation='relu'),
 830   tf.keras.layers.Dense(10, activation='softmax')
 831 ])
 832 
 833 model.compile(
 834     loss='sparse_categorical_crossentropy',
 835     optimizer=tf.keras.optimizers.Adam(0.001),
 836     metrics=['accuracy'],
 837 )
 838 
 839 print(model.summary())
 840 
 841 (train_images, train_labels), (test_images, test_labels) = mnist.load_data()
 842 
 843 train_images = train_images/255.0
 844 test_images = test_images/255.0
 845 
 846 model.fit(train_images, train_labels,
 847     epochs=4, batch_size=128, verbose=1)
 848 
 849 test_loss, test_accuracy = model.evaluate(test_images, test_labels)
 850 
 851 print(test_loss, test_accuracy)
 852 
 853 model.save("saved_mnist_model")
 854 
 855 ```
 856 
 857 ### Java program that uses Tensorflow C API
 858 
 859 ```java
 860 
 861 import jdk.incubator.foreign.*;
 862 import static jdk.incubator.foreign.MemoryAddress.*;
 863 import static org.tensorflow.c_api_h.*;
 864 import org.tensorflow.*;
 865 
 866 // simple program that loads saved model and prints basic info on operations in it
 867 
 868 public class TensorflowLoadSavedModel {
 869     public static void main(String... args) throws Exception {
 870         System.out.println("TensorFlow C library version: " + TF_Version().getUtf8String(0));
 871 
 872         if (args.length == 0) {
 873             System.err.println("java TensorflowLoadSavedModel <saved model dir>");
 874             System.exit(1);
 875         }
 876 
 877         try (var scope = ResourceScope.newConfinedScope()) {
 878             var allocator = SegmentAllocator.newNativeArena(scope);
 879             var graph = TF_NewGraph();
 880             var status = TF_NewStatus();
 881             var sessionOpts = TF_NewSessionOptions();
 882 
 883             var savedModelDir = allocator.allocateUtf8String(args[0]);
 884             var tags = allocator.allocate(C_POINTER, allocator.allocateUtf8String("serve"));
 885             var session = TF_LoadSessionFromSavedModel(sessionOpts, NULL, savedModelDir, tags, 1, graph, NULL, status);
 886 
 887             if (TF_GetCode(status) != TF_OK()) {
 888                 System.err.printf("cannot load session from saved model: %s\n",
 889                     TF_Message(status).getUtf8String(0));
 890             } else {
 891                 System.err.println("load session from saved model works!");
 892             }
 893 
 894             // print operations
 895             var size = allocator.allocate(C_LONG_LONG);
 896             var operation = NULL;
 897             while (!(operation = TF_GraphNextOperation(graph, size)).equals(NULL)) {
 898                 System.out.printf("%s : %s\n",
 899                     TF_OperationName(operation).getUtf8String(0),
 900                     TF_OperationOpType(operation).getUtf8String(0));
 901             }
 902 
 903             TF_DeleteGraph(graph);
 904             TF_DeleteSession(session, status);
 905             TF_DeleteSessionOptions(sessionOpts);
 906             TF_DeleteStatus(status);
 907         }
 908     }
 909 }
 910 
 911 ```
 912 
 913 ### Compiling and running the Java Tensorflow sample
 914 
 915 ```sh
 916 
 917 java --enable-native-access=ALL-UNNAMED --add-modules jdk.incubator.foreign \
 918    TensorflowLoadSavedModel.java saved_mnist_model
 919 
 920 ```
 921 
 922 ## Using time.h (Mac OS)
 923 
 924 ### jextract time.h
 925 
 926 
 927 ```sh
 928 
 929 jextract -t org.unix \
 930   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include \
 931    /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/time.h
 932 
 933 ```
 934 
 935 ### Java program that uses POSIX time library
 936 
 937 ```java
 938 
 939 import static org.unix.time_h.*;
 940 import static jdk.incubator.foreign.CLinker.*;
 941 import jdk.incubator.foreign.*;
 942 import org.unix.*;
 943 
 944 public class PanamaTime {
 945     public static void main(String[] args) {
 946         try (var scope = ResourceScope.newConfinedScope()) {
 947             var allocator = SegmentAllocator.newNativeArena(scope);
 948             var now = allocator.allocate(C_LONG, System.currentTimeMillis() / 1000);
 949             MemorySegment time = tm.allocate(scope);
 950             localtime_r(now, time);
 951             System.err.printf("Time = %d:%d\n", tm.tm_hour$get(time), tm.tm_min$get(time));
 952         }
 953     }
 954 }
 955 
 956 ```
 957 
 958 ### Compiling and running the time sample
 959 
 960 
 961 ```sh
 962 
 963 java --enable-native-access=ALL-UNNAMED --add-modules jdk.incubator.foreign PanamaTime.java
 964 
 965 ```
 966 
 967 ## Using libclang library (Mac OS)
 968 
 969 ### jextract Index.h
 970 
 971 ```sh
 972 
 973 # LIBCLANG_HOME is the directory where you've installed llvm 9.x or above
 974 
 975 jextract --source -t org.llvm.clang -lclang \
 976   -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/ \
 977   -I ${LIBCLANG_HOME}/include/ \
 978   -I ${LIBCLANG_HOME}/include/clang-c \
 979   ${LIBCLANG_HOME}/include/clang-c/Index.h
 980 javac --add-modules jdk.incubator.foreign org/llvm/clang/*.java
 981 
 982 ```
 983 
 984 ### Java program that uses libclang to print AST of a given C program
 985 
 986 ```java
 987 
 988 import jdk.incubator.foreign.*;
 989 import static jdk.incubator.foreign.MemoryAddress.NULL;
 990 import static org.llvm.clang.Index_h.*;
 991 import org.llvm.clang.*;
 992 
 993 public class ASTPrinter {
 994     private static String asJavaString(MemorySegment clangStr) {
 995         String str = clang_getCString(clangStr).getUtf8String(0);
 996         clang_disposeString(clangStr);
 997         return str;
 998     }
 999 
1000     public static void main(String[] args) {
1001         if (args.length == 0) {
1002             System.err.println("java ASTPrinter <C source or header>");
1003             System.exit(1);
1004         }
1005 
1006         try (var scope = ResourceScope.newConfinedScope()) {
1007             // parse the C header/source passed from the command line
1008             var index = clang_createIndex(0, 0);
1009             var allocator = SegmentAllocator.newNativeArena(scope);
1010             var tu = clang_parseTranslationUnit(index, allocator.allocateUtf8String(args[0]),
1011                     NULL, 0, NULL, 0, CXTranslationUnit_None());
1012             // array trick to update within lambda
1013             var level = new int[1];
1014             var visitor = new NativeSymbol[1];
1015 
1016             // clang Cursor visitor callback
1017             visitor[0] = CXCursorVisitor.allocate((cursor, parent, data) -> {
1018                 var kind = clang_getCursorKind(cursor);
1019                 var name = asJavaString(clang_getCursorSpelling(scope, cursor));
1020                 var kindName = asJavaString(clang_getCursorKindSpelling(scope, kind));
1021                 System.out.printf("%s %s %s", " ".repeat(level[0]), kindName, name);
1022                 var type = clang_getCursorType(scope, cursor);
1023                 if (CXType.kind$get(type) != CXType_Invalid()) {
1024                     var typeName = asJavaString(clang_getTypeSpelling(scope, type));
1025                     System.out.printf(" <%s>", typeName);
1026                 }
1027                 System.out.println();
1028 
1029                 // visit children
1030                 level[0]++;
1031                 clang_visitChildren(cursor, visitor[0], NULL);
1032                 level[0]--;
1033 
1034                 return CXChildVisit_Continue();
1035             }, scope);
1036 
1037             // get the AST root and visit it
1038             var root = clang_getTranslationUnitCursor(scope, tu);
1039             clang_visitChildren(root, visitor[0], NULL);
1040 
1041             clang_disposeTranslationUnit(tu);
1042             clang_disposeIndex(index);
1043         }
1044     }
1045 }
1046 
1047 ```
1048 
1049 ### Compiling and running the libclang sample
1050 
1051 ```sh
1052 
1053 java --enable-native-access=ALL-UNNAMED \
1054     -Djava.library.path=${LIBCLANG_HOME}/lib \
1055     --add-modules jdk.incubator.foreign \
1056     ASTPrinter.java $*
1057 
1058 ```