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