1 % Using Panama "foreign" JDK
   2 
   3 # Using Panama "foreign" JDK
   4 
   5 There are two ways to get a panama foreign branch JDK.
   6 
   7 1. Locally build "foreign" branch of panama repo [http://hg.openjdk.java.net/panama/dev/](http://hg.openjdk.java.net/panama/dev/)
   8 2. Download pre-built panama "foreign" early access binaries from [http://jdk.java.net/panama/](http://jdk.java.net/panama/)
   9 
  10 Using foreign function call in Java involves the following three steps:
  11 
  12 1. Use **jextract** tool to generate java interface for your C header file(s)
  13 2. Use **java.foreign** API to create ("bind") implementation for C header interfaces
  14 3. Invoke C functions via the jextracted Java interface
  15 
  16 ## Embedding Python interpreter in your Java program (Mac OS)
  17 
  18 ### jextract a Jar file for Python.h
  19 
  20 ```sh
  21 
  22 jextract -l python2.7 \
  23   -rpath /System/Library/Frameworks/Python.framework/Versions/2.7/lib \
  24   --exclude-symbols .*_FromFormatV\|_.*\|PyOS_vsnprintf\|.*_VaParse.*\|.*_VaBuild.*\|PyBuffer_SizeFromFormat\|vasprintf\|vfprintf\|vprintf\|vsprintf \
  25   -t org.python \
  26   /usr/include/stdio.h /usr/include/stdlib.h /usr/include/python2.7/Python.h \
  27   -o python.jar
  28 
  29 ```
  30 
  31 ### Java program that uses extracted Python interface
  32 
  33 ```java
  34 
  35 // import java.foreign packages
  36 import java.foreign.Libraries;
  37 import java.foreign.Scope;
  38 import java.foreign.memory.Pointer;
  39 
  40 // import jextracted python 'header' classes
  41 import static org.python.Python_h.*;
  42 import static org.python.pythonrun_h.*;
  43 
  44 public class PythonMain {
  45     public static void main(String[] args) {
  46         Py_Initialize();
  47         try (Scope s = Scope.newNativeScope()) {
  48             PyRun_SimpleStringFlags(s.allocateCString(
  49                 "print(sum([33, 55, 66])); print('Hello from Python!')\n"),
  50                 Pointer.nullPointer());
  51         }
  52         Py_Finalize();
  53     }
  54 }
  55 
  56 ```
  57 
  58 ### Running the Java code that calls Python interpreter
  59 
  60 ```sh
  61 
  62 javac -cp pythor.jar PythonMain.java
  63 
  64 java -cp python.jar:. PythonMain
  65 
  66 ```
  67 
  68 ## Embedding Python interpreter in your Java program (Ubuntu 16.04)
  69 
  70 ### jextract a Jar file for Python.h
  71 
  72 ```sh
  73 
  74 jextract -l python2.7 \
  75   -rpath /usr/lib/python2.7/config-x86_64-linux-gnu \
  76   --exclude-symbols .*_FromFormatV\|_.*\|PyOS_vsnprintf\|.*_VaParse.*\|.*_VaBuild.*\|PyBuffer_SizeFromFormat\|vasprintf\|vfprintf\|vprintf\|vsprintf \
  77   -t org.python \
  78   /usr/include/stdio.h /usr/include/stdlib.h /usr/include/python2.7/Python.h \
  79   -o python.jar
  80 
  81 ```
  82 
  83 ### Compiling and Running Python Java example
  84 
  85 Follow the instructions from the Mac OS section
  86 
  87 ## Using BLAS library
  88 
  89 BLAS is a popular library that allows fast matrix and vector computation: [http://www.netlib.org/blas/](http://www.netlib.org/blas/).
  90 
  91 ### Installing OpenBLAS (Mac OS)
  92 
  93 On Mac, blas is available as part of the OpenBLAS library: [https://github.com/xianyi/OpenBLAS/wiki](https://github.com/xianyi/OpenBLAS/wiki)
  94 
  95 OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version.
  96 
  97 You can install openblas using HomeBrew
  98 
  99 ```sh
 100 
 101 brew install openblas
 102 
 103 ```
 104 
 105 It installs include and lib directories under /usr/local/opt/openblas
 106 
 107 ### Installing OpenBLAS (Ubuntu 16.04)
 108 
 109 On Ubuntu, blas is distributed as part of the atlas library: [http://math-atlas.sourceforge.net/](http://math-atlas.sourceforge.net/).
 110 
 111 You can install atlas using apt
 112 
 113 ```sh
 114 
 115 sudo apt-get install libatlas-base-dev
 116 
 117 ```
 118 
 119 This command will install include files under `/usr/include/atlas` and corresponding libraries under `/usr/lib/atlas-dev`.
 120 
 121 
 122 ### jextracting cblas.h (MacOS)
 123 
 124 The following command can be used to extract cblas.h on MacOs
 125 
 126 ```sh
 127 
 128 jextract -C "-D FORCE_OPENBLAS_COMPLEX_STRUCT" \
 129   -L /usr/local/opt/openblas/lib -I /usr/local/opt/openblas \
 130   -l openblas -t blas -infer-rpath /usr/local/opt/openblas/include/cblas.h \
 131   -o cblas.jar
 132 
 133 ```
 134 
 135 The FORCE_OPENBLAS_COMPLEX_STRUCT define is needed because jextract does not
 136 yet handle C99 `_Complex` types. The rest of the options are standard ones.
 137 
 138 ### jextracting cblas.h (Ubuntu 16.04)
 139 
 140 The following command can be used to extract cblas.h on Ubuntu
 141 
 142 ```sh
 143 
 144 jextract -L /usr/lib/atlas-base -I /usr/include/atlas/ \
 145    -l cblas -t blas -infer-rpath \
 146    /usr/include/atlas/cblas.h -o cblas.jar
 147 
 148 ```
 149 
 150 ### Java sample code that uses cblas library
 151 
 152 ```java
 153 
 154 import blas.cblas;
 155 
 156 import static blas.cblas_h.*;
 157 
 158 import java.foreign.NativeTypes;
 159 import java.foreign.Scope;
 160 import java.foreign.memory.Array;
 161 
 162 public class TestBlas {
 163    public static void main(String[] args) {
 164        @cblas.CBLAS_ORDER int Layout;
 165        @cblas.CBLAS_TRANSPOSE int transa;
 166 
 167        double alpha, beta;
 168        int m, n, lda, incx, incy, i;
 169 
 170        Layout = CblasColMajor;
 171        transa = CblasNoTrans;
 172 
 173        m = 4; /* Size of Column ( the number of rows ) */
 174        n = 4; /* Size of Row ( the number of columns ) */
 175        lda = 4; /* Leading dimension of 5 * 4 matrix is 5 */
 176        incx = 1;
 177        incy = 1;
 178        alpha = 1;
 179        beta = 0;
 180 
 181        try (Scope sc = Scope.newNativeScope()){
 182            Array<Double> a = sc.allocateArray(NativeTypes.DOUBLE, m * n);
 183            Array<Double> x = sc.allocateArray(NativeTypes.DOUBLE, n);
 184            Array<Double> y = sc.allocateArray(NativeTypes.DOUBLE, n);
 185            /* The elements of the first column */
 186            a.set(0, 1.0);
 187            a.set(1, 2.0);
 188            a.set(2, 3.0);
 189            a.set(3, 4.0);
 190            /* The elements of the second column */
 191            a.set(m, 1.0);
 192            a.set(m + 1, 1.0);
 193            a.set(m + 2, 1.0);
 194            a.set(m + 3, 1.0);
 195            /* The elements of the third column */
 196            a.set(m * 2, 3.0);
 197            a.set(m * 2 + 1, 4.0);
 198            a.set(m * 2 + 2, 5.0);
 199            a.set(m * 2 + 3, 6.0);
 200            /* The elements of the fourth column */
 201            a.set(m * 3, 5.0);
 202            a.set(m * 3 + 1, 6.0);
 203            a.set(m * 3 + 2, 7.0);
 204            a.set(m * 3 + 3, 8.0);
 205            /* The elemetns of x and y */
 206            x.set(0, 1.0);
 207            x.set(1, 2.0);
 208            x.set(2, 1.0);
 209            x.set(3, 1.0);
 210            y.set(0, 0.0);
 211            y.set(1, 0.0);
 212            y.set(2, 0.0);
 213            y.set(3, 0.0);
 214 
 215            cblas_dgemv(Layout, transa, m, n, alpha, a.elementPointer(), lda, x.elementPointer(), incx, beta,
 216                    y.elementPointer(), incy);
 217            /* Print y */
 218            for (i = 0; i < n; i++)
 219                System.out.print(String.format(" y%d = %f\n", i, y.get(i)));
 220        }
 221    }
 222 }
 223 
 224 ```
 225 
 226 ### Compiling and running the above cblas samples
 227 
 228 ```sh
 229 
 230 javac -cp cblas.jar TestBlas.java
 231 
 232 java -cp cblas.jar:. TestBlas
 233 
 234 ```
 235 
 236 ## Using LAPACK library (Ubuntu)
 237 
 238 On Ubuntu, the same steps used to install the blas (via atlas) library also install headers and libraries for the LAPACK library, a linear algebra computation library built on top of blas.
 239 
 240 ### jextracting clapack.h (Ubuntu 16.04)
 241 
 242 The following command can be used to extract the LAPACK header:
 243 
 244 ```sh
 245 
 246 jextract -L /usr/lib/atlas-base/atlas -I /usr/include/atlas/ \
 247    -l lapack -t lapack -infer-rpath /usr/include/atlas/clapack.h -o clapack.jar
 248 
 249 ```
 250 
 251 ### Java sample code that uses LAPACK library
 252 
 253 ```java
 254 import java.foreign.NativeTypes;
 255 import java.foreign.Scope;
 256 import java.foreign.memory.Array;
 257 
 258 import static lapack.clapack_h.*;
 259 import static lapack.cblas_h.*;
 260 
 261 public class TestLapack {
 262     public static void main(String[] args) {
 263 
 264         /* Locals */
 265         try (Scope sc = Scope.newNativeScope()) {
 266             Array<Double> A = sc.allocateArray(NativeTypes.DOUBLE, new double[]{
 267                     1, 2, 3, 4, 5, 1, 3, 5, 2, 4, 1, 4, 2, 5, 3
 268             });
 269             Array<Double> b = sc.allocateArray(NativeTypes.DOUBLE, new double[]{
 270                     -10, 12, 14, 16, 18, -3, 14, 12, 16, 16
 271             });
 272             int info, m, n, lda, ldb, nrhs;
 273 
 274             /* Initialization */
 275             m = 5;
 276             n = 3;
 277             nrhs = 2;
 278             lda = 5;
 279             ldb = 5;
 280 
 281             /* Print Entry Matrix */
 282             print_matrix_colmajor("Entry Matrix A", m, n, A, lda );
 283             /* Print Right Rand Side */
 284             print_matrix_colmajor("Right Hand Side b", n, nrhs, b, ldb );
 285             System.out.println();
 286 
 287             /* Executable statements */
 288             //            printf( "LAPACKE_dgels (col-major, high-level) Example Program Results\n" );
 289             /* Solve least squares problem*/
 290             info = clapack_dgels(CblasColMajor, CblasNoTrans, m, n, nrhs, A.elementPointer(), lda, b.elementPointer(), ldb);
 291 
 292             /* Print Solution */
 293             print_matrix_colmajor("Solution", n, nrhs, b, ldb );
 294             System.out.println();
 295             System.exit(info);
 296         }
 297     }
 298 
 299     static void print_matrix_colmajor(String msg, int m, int n, Array<Double> mat, int ldm) {
 300         int i, j;
 301         System.out.printf("\n %s\n", msg);
 302 
 303         for( i = 0; i < m; i++ ) {
 304             for( j = 0; j < n; j++ ) System.out.printf(" %6.2f", mat.get(i+j*ldm));
 305             System.out.printf( "\n" );
 306         }
 307     }
 308 }
 309 ```
 310 
 311 ### Compiling and running the above LAPACK sample
 312 
 313 ```sh
 314 
 315 javac -cp clapack.jar TestLapack.java
 316 
 317 java -cp clapack.jar:. TestLapack
 318 
 319 ```
 320 
 321 ## Using LAPACK library (Mac OS)
 322 
 323 On Mac OS, lapack is installed under /usr/local/opt/lapack directory.
 324 
 325 ### jextracting lapacke.h
 326 
 327 The following command can be used to extract the LAPACK header. These are too many symbols in lapacke.h
 328 and so jextract throws too many constant pool entries (IllegalArgumentException). To workaround, we
 329 include only the symbols used in the Java sample code below.
 330 
 331 ```sh
 332 
 333 jextract --include-symbols LAPACKE_dgels\|LAPACK_COL_MAJOR \
 334   -L /usr/local/opt/lapack/lib -I /usr/local/opt/lapack/ \
 335   -l lapacke -t lapack -infer-rpath /usr/local/opt/lapack/include/lapacke.h -o clapack.jar
 336 
 337 ```
 338 ### Java sample code that uses LAPACK library
 339 
 340 ```java
 341 
 342 import java.foreign.NativeTypes;
 343 import java.foreign.Scope;
 344 import java.foreign.memory.Array;
 345 
 346 import static lapack.lapacke_h.*;
 347 
 348 public class TestLapack {
 349     public static void main(String[] args) {
 350 
 351         /* Locals */
 352         try (Scope sc = Scope.newNativeScope()) {
 353             Array<Double> A = sc.allocateArray(NativeTypes.DOUBLE, new double[]{
 354                     1, 2, 3, 4, 5, 1, 3, 5, 2, 4, 1, 4, 2, 5, 3
 355             });
 356             Array<Double> b = sc.allocateArray(NativeTypes.DOUBLE, new double[]{
 357                     -10, 12, 14, 16, 18, -3, 14, 12, 16, 16
 358             });
 359             int info, m, n, lda, ldb, nrhs;
 360 
 361             /* Initialization */
 362             m = 5;
 363             n = 3;
 364             nrhs = 2;
 365             lda = 5;
 366             ldb = 5;
 367 
 368             /* Print Entry Matrix */
 369             print_matrix_colmajor("Entry Matrix A", m, n, A, lda );
 370             /* Print Right Rand Side */
 371             print_matrix_colmajor("Right Hand Side b", n, nrhs, b, ldb );
 372             System.out.println();
 373 
 374             /* Executable statements */
 375             //            printf( "LAPACKE_dgels (col-major, high-level) Example Program Results\n" );
 376             /* Solve least squares problem*/
 377             info = LAPACKE_dgels(LAPACK_COL_MAJOR, (byte)'N', m, n, nrhs, A.elementPointer(), lda, b.elementPointer(), ldb);
 378 
 379             /* Print Solution */
 380             print_matrix_colmajor("Solution", n, nrhs, b, ldb );
 381             System.out.println();
 382             System.exit(info);
 383         }
 384     }
 385 
 386     static void print_matrix_colmajor(String msg, int m, int n, Array<Double> mat, int ldm) {
 387         int i, j;
 388         System.out.printf("\n %s\n", msg);
 389 
 390         for( i = 0; i < m; i++ ) {
 391             for( j = 0; j < n; j++ ) System.out.printf(" %6.2f", mat.get(i+j*ldm));
 392             System.out.printf( "\n" );
 393         }
 394     }
 395 }
 396 
 397 ```
 398 
 399 ### Compiling and running the above LAPACK sample
 400 
 401 ```sh
 402 
 403 javac -cp clapack.jar TestLapack.java
 404 
 405 java -cp clapack.jar:. TestLapack
 406 
 407 ```
 408 
 409 ## Using libproc library to list processes from Java (Mac OS)
 410 
 411 ### jextract a jar file for libproc.h
 412 
 413 jextract -t org.unix -lproc -rpath /usr/lib -o libproc.jar /usr/include/libproc.h
 414 
 415 ### Java program that uses libproc to list processes
 416 
 417 ```java
 418 
 419 import java.foreign.*;
 420 import java.foreign.memory.*;
 421 import static org.unix.libproc_h.*;
 422 
 423 public class LibprocMain {
 424     private static final int NAME_BUF_MAX = 256;
 425 
 426     public static void main(String[] args) {
 427         // Scope for native allocations
 428         try (Scope s = Scope.newNativeScope()) {
 429             // get the number of processes
 430             int numPids = proc_listallpids(Pointer.nullPointer(), 0);
 431             // allocate an array
 432             Array<Integer> pids = s.allocateArray(NativeTypes.INT32, numPids);
 433             // list all the pids into the native array
 434             proc_listallpids(pids.elementPointer(), numPids);
 435             // convert native array to java array
 436             int[] jpids = pids.toArray(num -> new int[num]);
 437             // buffer for process name
 438             Pointer<Byte> nameBuf = s.allocate(NativeTypes.INT8, NAME_BUF_MAX);
 439             for (int i = 0; i < jpids.length; i++) {
 440                 int pid = jpids[i];
 441                 // get the process name
 442                 proc_name(pid, nameBuf, NAME_BUF_MAX);
 443                 String procName = Pointer.toString(nameBuf);
 444                 // print pid and process name
 445                 System.out.printf("%d %s\n", pid, procName);
 446             }
 447         }
 448     }
 449 }
 450 
 451 ```
 452 
 453 ### Running the Java code that uses libproc
 454 
 455 ```sh
 456 
 457 javac -cp libproc.jar LibprocMain.java
 458 
 459 java -cp libproc.jar:. LibprocMain
 460 
 461 ```
 462 
 463 ## Using readline library from Java code (Mac OS)
 464 
 465 ### jextract a jar file for readline.h
 466 
 467 ```sh
 468 
 469 jextract -l readline -rpath /usr/local/opt/readline/lib/ \
 470     -t org.unix \
 471     /usr/include/readline/readline.h /usr/include/_stdio.h \
 472     --exclude-symbol readline_echoing_p -o readline.jar
 473 
 474 ```
 475 
 476 ### Java code that uses readline
 477 
 478 ```java
 479 
 480 import java.foreign.*;
 481 import java.foreign.memory.*;
 482 import static org.unix.readline_h.*;
 483 
 484 public class Readline {
 485     public static void main(String[] args) {
 486         // Scope for native allocations
 487         try (Scope s = Scope.newNativeScope()) {
 488             // allocate C memory initialized with Java string content
 489             var pstr = s.allocateCString("name? ");
 490 
 491             // call "readline" API
 492             var p = readline(pstr);
 493 
 494             // print char* as is
 495             System.out.println(p);
 496             // convert char* ptr from readline as Java String & print it
 497             System.out.println(Pointer.toString(p));
 498         }
 499     }
 500 }
 501 
 502 ```
 503 
 504 ### Running the java code that uses readline
 505 
 506 ```
 507 
 508 javac -cp readline.jar Readline.java
 509 
 510 java -cp readline.jar:. Readline
 511 
 512 ```
 513 
 514 ## Using unistd.h from Java code (Linux)
 515 
 516 ### jextract a jar file for unistd.h
 517 
 518 ```sh
 519 
 520 jextract /usr/include/unistd.h -t org.unix -o unistd.jar
 521 
 522 ```
 523 
 524 ### Java code that calls getpid
 525 
 526 ```java
 527 
 528 import java.foreign.*;
 529 import java.lang.invoke.*;
 530 import org.unix.unistd;
 531 
 532 
 533 public class Getpid {
 534     public static void main(String[] args) {
 535         // bind unistd interface
 536         var u = Libraries.bind(MethodHandles.lookup(), unistd.class);
 537         // call getpid from the unistd.h
 538         System.out.println(u.getpid());
 539         // check process id from Java API!
 540         System.out.println(ProcessHandle.current().pid());
 541     }
 542 }
 543 
 544 ```
 545 
 546 ### Running the Java code that uses getpid
 547 
 548 ```sh
 549 
 550 javac -cp unistd.jar Getpid.java
 551 
 552 java -cp unistd.jar:. Getpid
 553 
 554 ```
 555 
 556 
 557 ## Using OpenGL graphic library (Ubuntu 16.04)
 558 
 559 OpenGL is a popular portable graphic library: [https://www.opengl.org/](https://www.opengl.org/)
 560 
 561 ### Installing OpenGL (Ubuntu 16.04)
 562 
 563 Installing relevant OpenGL headers and libraries can be a bit tricky, as it depends on what graphic card is installed on the target platform. The following instruction assume that the standard version of OpenGL is used (e.g. mesa), rather than a proprietary one (Nvidia or AMD), although the changes to get these working are rather small.
 564 
 565 OpenGL is always coupled with a bunch of other libraries, namely GLU and glut. You can install all those libraries using `apt`, as follows:
 566 
 567 ```sh
 568 
 569 sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev
 570 
 571 ```
 572 
 573 If the installation was successful, OpenGL headers can be found under `/usr/include/GL`, while libraries can be found in the folder `/usr/lib/x86_64-linux-gnu/`.
 574 
 575 ### jextracting OpenGL (Ubuntu 16.04)
 576 
 577 To extract the opengl libraries the following command suffices:
 578 
 579 ```sh
 580 
 581 jextract -L /usr/lib/x86_64-linux-gnu  -l glut -l GLU -l GL --infer-rpath -t opengl -o opengl.jar /usr/include/GL/glut.h
 582 
 583 ```
 584 
 585 Since glut depends on the other libraries (GLU and GL), it is not necessary to give additional headers to jextract.
 586 
 587 ### Java sample code that uses the OpenGL library
 588 
 589 ```java
 590 import java.foreign.Libraries;
 591 import java.foreign.NativeTypes;
 592 import java.foreign.Scope;
 593 import java.foreign.memory.Array;
 594 import java.foreign.memory.Pointer;
 595 import java.lang.invoke.MethodHandles;
 596 
 597 import opengl.*;
 598 
 599 import javax.imageio.ImageIO;
 600 
 601 public class Teapot {
 602     static gl gl = Libraries.bind(MethodHandles.lookup(), gl.class);
 603     static freeglut_std glut = Libraries.bind(MethodHandles.lookup(), freeglut_std.class);
 604 
 605     float rot = 0;
 606 
 607     Teapot(Scope sc) {
 608         // Misc Parameters
 609         Array<Float> pos = sc.allocateArray(NativeTypes.FLOAT, new float[] {0.0f, 15.0f, -15.0f, 0});
 610         Array<Float> spec = sc.allocateArray(NativeTypes.FLOAT, new float[] {1, 1, 1, 0});
 611         Array<Float> shini = sc.allocateArray(NativeTypes.FLOAT, new float[] {113});
 612 
 613         // Reset Background
 614         gl.glClearColor(0, 0, 0, 0);
 615 
 616         // Setup Lighting
 617         gl.glShadeModel(gl.GL_SMOOTH());
 618         gl.glLightfv(gl.GL_LIGHT0(), gl.GL_POSITION(), pos.elementPointer());
 619         gl.glLightfv(gl.GL_LIGHT0(), gl.GL_AMBIENT(), spec.elementPointer());
 620         gl.glLightfv(gl.GL_LIGHT0(), gl.GL_DIFFUSE(), spec.elementPointer());
 621         gl.glLightfv(gl.GL_LIGHT0(), gl.GL_SPECULAR(), spec.elementPointer());
 622         gl.glMaterialfv(gl.GL_FRONT(), gl.GL_SHININESS(), shini.elementPointer());
 623         gl.glEnable(gl.GL_LIGHTING());
 624         gl.glEnable(gl.GL_LIGHT0());
 625         gl.glEnable(gl.GL_DEPTH_TEST());
 626     }
 627 
 628     void display() {
 629         gl.glClear(gl.GL_COLOR_BUFFER_BIT() | gl.GL_DEPTH_BUFFER_BIT());
 630         gl.glPushMatrix();
 631         gl.glRotatef(-20, 1, 1, 0);
 632         gl.glRotatef(rot, 0, 1, 0);
 633         glut.glutSolidTeapot(0.5);
 634         gl.glPopMatrix();
 635         glut.glutSwapBuffers();
 636     }
 637 
 638         void onIdle() {
 639         rot += 0.1;
 640         glut.glutPostRedisplay();
 641     }
 642 
 643     public static void main(String[] args) {
 644         try (Scope sc = Scope.newNativeScope()) {
 645             Pointer<Integer> argc = sc.allocate(NativeTypes.INT32);
 646             argc.set(0);
 647             glut.glutInit(argc, Pointer.nullPointer());
 648             glut.glutInitDisplayMode(glut.GLUT_DOUBLE() | glut.GLUT_RGBA() | glut.GLUT_DEPTH());
 649             glut.glutInitWindowSize(900, 900);
 650             glut.glutCreateWindow(sc.allocateCString("Hello Panama!"));
 651             Teapot teapot = new Teapot(sc);
 652             glut.glutDisplayFunc(sc.allocateCallback(teapot::display));
 653             glut.glutIdleFunc(sc.allocateCallback(teapot::onIdle));
 654             glut.glutMainLoop();
 655         }
 656     }
 657 }
 658 ```
 659 ### Running the Java code that uses OpenGL
 660 
 661 ```sh
 662 
 663 javac -cp opengl.jar Teapot.java
 664 
 665 java -cp opengl.jar:. Teapot
 666 
 667 ```
 668 
 669 
 670 ## Using TensorFlow C API (Mac OS)
 671 
 672 Quoted from [https://www.tensorflow.org/install/lang_c](https://www.tensorflow.org/install/lang_c)
 673 
 674 "TensorFlow provides a C API that can be used to build bindings for other
 675 languages. The API is defined in c_api.h and designed for simplicity and
 676 uniformity rather than convenience."
 677 
 678 
 679 ### Installing libtensorflow
 680 
 681 You can follow the setup procedure as described in the above page.
 682 
 683 Alternatively, on Mac, you can install libtensorflow using HomeBrew
 684 
 685 ```sh
 686 
 687 brew install libtensorflow
 688 
 689 ```
 690 
 691 Tensorflow ship the libtensorflow with an .so extension, this doesn't work
 692 well for java on MacOS as java expect .dylib extension. To work around this,
 693 create a symbolic link.
 694 
 695 ```sh
 696 
 697 sudo ln -s /usr/local/lib/libtensorflow.so /usr/local/lib/libtensorflow.dylib
 698 
 699 ```
 700 
 701 ### jextracting libtensorflow c_api.h
 702 
 703 The following command can be used to extract c_api.h.
 704 
 705 ```sh
 706 
 707 jextract -C -x -C c++  \
 708         -L /usr/local/lib -l tensorflow -infer-rpath \
 709         -o tf.jar -t org.tensorflow.panama \
 710         /usr/local/include/tensorflow/c/c_api.h
 711 
 712 ```
 713 
 714 The caveat to extract tensorflow C API is that it declare function prototype
 715 without argument in C++ style, for example, TF_Version(), which is considered
 716 incomplete C function prototype instead of C style as in TF_Version(void). An
 717 incomplete function prototype will become vararg funciton. To avoid that, we
 718 need to pass clang '-x c++' options to jextract with '-C -x -C c++'
 719 
 720 
 721 ### Java sample code that uses tensorflow library
 722 
 723 ```java
 724 
 725 import java.foreign.NativeTypes;
 726 import java.foreign.Scope;
 727 import java.foreign.memory.Array;
 728 import java.foreign.memory.LayoutType;
 729 import java.foreign.memory.Pointer;
 730 import org.tensorflow.panama.c_api.TF_DataType;
 731 import org.tensorflow.panama.c_api.TF_Graph;
 732 import org.tensorflow.panama.c_api.TF_Operation;
 733 import org.tensorflow.panama.c_api.TF_OperationDescription;
 734 import org.tensorflow.panama.c_api.TF_Output;
 735 import org.tensorflow.panama.c_api.TF_Session;
 736 import org.tensorflow.panama.c_api.TF_SessionOptions;
 737 import org.tensorflow.panama.c_api.TF_Status;
 738 import org.tensorflow.panama.c_api.TF_Tensor;
 739 
 740 import static org.tensorflow.panama.c_api_h.*;
 741 
 742 public class TensorFlowExample {
 743     static Pointer<TF_Operation> PlaceHolder(Pointer<TF_Graph> graph, Pointer<TF_Status> status,
 744                                       @TF_DataType int dtype, String name) {
 745         try (var s = Scope.newNativeScope()) {
 746             Pointer<TF_OperationDescription> desc = TF_NewOperation(graph,
 747                     s.allocateCString("Placeholder"), s.allocateCString(name));
 748             TF_SetAttrType(desc, s.allocateCString("dtype"), TF_FLOAT);
 749             return TF_FinishOperation(desc, status);
 750         }
 751     }
 752 
 753     static Pointer<TF_Operation> ConstValue(Pointer<TF_Graph> graph, Pointer<TF_Status> status,
 754                                 Pointer<TF_Tensor> tensor, String name) {
 755         try (var s = Scope.newNativeScope()) {
 756             Pointer<TF_OperationDescription> desc = TF_NewOperation(graph,
 757                     s.allocateCString("Const"), s.allocateCString(name));
 758             TF_SetAttrTensor(desc, s.allocateCString("value"), tensor, status);
 759             TF_SetAttrType(desc, s.allocateCString("dtype"), TF_TensorType(tensor));
 760             return TF_FinishOperation(desc, status);
 761         }
 762     }
 763 
 764     static Pointer<TF_Operation> Add(Pointer<TF_Graph> graph, Pointer<TF_Status> status,
 765                               Pointer<TF_Operation> one, Pointer<TF_Operation> two,
 766                               String name) {
 767         try (var s = Scope.newNativeScope()) {
 768             Pointer<TF_OperationDescription> desc = TF_NewOperation(graph,
 769                     s.allocateCString("AddN"), s.allocateCString(name));
 770             Array<TF_Output> add_inputs = s.allocateArray(
 771                     LayoutType.ofStruct(TF_Output.class),2);
 772             add_inputs.get(0).oper$set(one);
 773             add_inputs.get(0).index$set(0);
 774             add_inputs.get(1).oper$set(two);
 775             add_inputs.get(1).index$set(0);
 776             TF_AddInputList(desc, add_inputs.elementPointer(), 2);
 777             return TF_FinishOperation(desc, status);
 778         }
 779     }
 780 
 781     public static void main(String... args) {
 782         System.out.println("TensorFlow C library version: " + Pointer.toString(TF_Version()));
 783 
 784         Pointer<TF_Graph> graph = TF_NewGraph();
 785         Pointer<TF_SessionOptions> options = TF_NewSessionOptions();
 786         Pointer<TF_Status> status = TF_NewStatus();
 787         Pointer<TF_Session> session = TF_NewSession(graph, options, status);
 788 
 789         float in_val_one = 4.0f;
 790         float const_two = 2.0f;
 791 
 792         Pointer<TF_Tensor> tensor_in = TF_AllocateTensor(TF_FLOAT, Pointer.nullPointer(), 0, Float.BYTES);
 793         TF_TensorData(tensor_in).cast(NativeTypes.FLOAT).set(in_val_one);
 794         Pointer<TF_Tensor> tensor_const_two = TF_AllocateTensor(TF_FLOAT, Pointer.nullPointer(), 0, Float.BYTES);
 795         TF_TensorData(tensor_const_two).cast(NativeTypes.FLOAT).set(const_two);
 796 
 797         // Operations
 798         Pointer<TF_Operation> feed = PlaceHolder(graph, status, TF_FLOAT, "feed");
 799         Pointer<TF_Operation> two = ConstValue(graph, status, tensor_const_two, "const");
 800         Pointer<TF_Operation> add = Add(graph, status, feed, two, "add");
 801 
 802 
 803         try (var s = Scope.newNativeScope()) {
 804             var ltPtrTensor = LayoutType.ofStruct(TF_Tensor.class).pointer();
 805 
 806             // Session Inputs
 807             TF_Output input_operations = s.allocateStruct(TF_Output.class);
 808             input_operations.oper$set(feed);
 809             input_operations.index$set(0);
 810             Pointer<Pointer<TF_Tensor>> input_tensors = s.allocate(ltPtrTensor);
 811             input_tensors.set(tensor_in);
 812 
 813             // Session Outputs
 814             TF_Output output_operations = s.allocateStruct(TF_Output.class);
 815             output_operations.oper$set(add);
 816             output_operations.index$set(0);
 817             Pointer<Pointer<TF_Tensor>> output_tensors = s.allocate(ltPtrTensor);
 818             TF_SessionRun(session, Pointer.nullPointer(),
 819                 // Inputs
 820                 input_operations.ptr(), input_tensors, 1,
 821                 // Outputs
 822                 output_operations.ptr(), output_tensors, 1,
 823                 // Target operations
 824                 Pointer.nullPointer(), 0, Pointer.nullPointer(),
 825                 status);
 826 
 827             System.out.println(String.format("Session Run Status: %d - %s",
 828                     TF_GetCode(status), Pointer.toString(TF_Message(status))));
 829             Pointer<TF_Tensor> tensor_out = output_tensors.get();
 830             System.out.println("Output Tensor Type: " + TF_TensorType(tensor_out));
 831             float outval = TF_TensorData(tensor_out).cast(NativeTypes.FLOAT).get();
 832             System.out.println("Output Tensor Value: " + outval);
 833 
 834             TF_CloseSession(session, status);
 835             TF_DeleteSession(session, status);
 836 
 837             TF_DeleteSessionOptions(options);
 838 
 839             TF_DeleteGraph(graph);
 840 
 841             TF_DeleteTensor(tensor_in);
 842             TF_DeleteTensor(tensor_out);
 843             TF_DeleteTensor(tensor_const_two);
 844 
 845             TF_DeleteStatus(status);
 846         }
 847     }
 848 }
 849 
 850 ```
 851 
 852 ### Compiling and running the above TensorFlow sample
 853 
 854 ```sh
 855 
 856 javac -cp tf.jar TensorFlowExample.java
 857 
 858 java -cp tf.jar:. TensorFlowExample
 859 
 860 ```