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/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/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 ### Note: This sample fails because of too big UTF-8 String in NativeHeader annotation
 466 
 467 ### jextract a jar file for readline.h
 468 
 469 ```sh
 470 
 471 jextract -l readline -rpath /usr/local/opt/readline/lib/ \
 472     -t org.unix \
 473     /usr/include/readline/readline.h \
 474     --exclude-symbol readline_echoing_p -o readline.jar
 475 
 476 ```
 477 
 478 ### Java code that uses readline
 479 
 480 ```java
 481 
 482 import java.foreign.*;
 483 import java.foreign.memory.*;
 484 import static org.unix.readline_h.*;
 485 
 486 public class Readline {
 487     public static void main(String[] args) {
 488         // Scope for native allocations
 489         try (Scope s = Scope.newNativeScope()) {
 490             // allocate C memory initialized with Java string content
 491             var pstr = s.allocateCString("name? ");
 492 
 493             // call "readline" API
 494             var p = readline(pstr);
 495 
 496             // print char* as is
 497             System.out.println(p);
 498             // convert char* ptr from readline as Java String & print it
 499             System.out.println(Pointer.toString(p));
 500         }
 501     }
 502 }
 503 
 504 ```
 505 
 506 ### Running the java code that uses readline
 507 
 508 ```
 509 
 510 javac -cp readline.jar Readline.java
 511 
 512 java -cp readline.jar:. Readline
 513 
 514 ```
 515 
 516 ## Using unistd.h from Java code (Linux)
 517 
 518 ### jextract a jar file for unistd.h
 519 
 520 ```sh
 521 
 522 jextract /usr/include/unistd.h -t org.unix -o unistd.jar
 523 
 524 ```
 525 
 526 ### Java code that calls getpid
 527 
 528 ```java
 529 
 530 import java.foreign.*;
 531 import java.lang.invoke.*;
 532 import org.unix.unistd;
 533 
 534 
 535 public class Getpid {
 536     public static void main(String[] args) {
 537         // bind unistd interface
 538         var u = Libraries.bind(MethodHandles.lookup(), unistd.class);
 539         // call getpid from the unistd.h
 540         System.out.println(u.getpid());
 541         // check process id from Java API!
 542         System.out.println(ProcessHandle.current().pid());
 543     }
 544 }
 545 
 546 ```
 547 
 548 ### Running the Java code that uses getpid
 549 
 550 ```sh
 551 
 552 javac -cp unistd.jar Getpid.java
 553 
 554 java -cp unistd.jar:. Getpid
 555 
 556 ```
 557 
 558 
 559 ## Using OpenGL graphic library (Ubuntu 16.04)
 560 
 561 OpenGL is a popular portable graphic library: [https://www.opengl.org/](https://www.opengl.org/)
 562 
 563 ### Installing OpenGL (Ubuntu 16.04)
 564 
 565 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.
 566 
 567 OpenGL is always coupled with a bunch of other libraries, namely GLU and glut. You can install all those libraries using `apt`, as follows:
 568 
 569 ```sh
 570 
 571 sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev
 572 
 573 ```
 574 
 575 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/`.
 576 
 577 ### jextracting OpenGL (Ubuntu 16.04)
 578 
 579 To extract the opengl libraries the following command suffices:
 580 
 581 ```sh
 582 
 583 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
 584 
 585 ```
 586 
 587 Since glut depends on the other libraries (GLU and GL), it is not necessary to give additional headers to jextract.
 588 
 589 ### Java sample code that uses the OpenGL library
 590 
 591 ```java
 592 import java.foreign.Libraries;
 593 import java.foreign.NativeTypes;
 594 import java.foreign.Scope;
 595 import java.foreign.memory.Array;
 596 import java.foreign.memory.Pointer;
 597 import java.lang.invoke.MethodHandles;
 598 
 599 import opengl.*;
 600 
 601 import javax.imageio.ImageIO;
 602 
 603 public class Teapot {
 604     static gl gl = Libraries.bind(MethodHandles.lookup(), gl.class);
 605     static freeglut_std glut = Libraries.bind(MethodHandles.lookup(), freeglut_std.class);
 606 
 607     float rot = 0;
 608 
 609     Teapot(Scope sc) {
 610         // Misc Parameters
 611         Array<Float> pos = sc.allocateArray(NativeTypes.FLOAT, new float[] {0.0f, 15.0f, -15.0f, 0});
 612         Array<Float> spec = sc.allocateArray(NativeTypes.FLOAT, new float[] {1, 1, 1, 0});
 613         Array<Float> shini = sc.allocateArray(NativeTypes.FLOAT, new float[] {113});
 614 
 615         // Reset Background
 616         gl.glClearColor(0, 0, 0, 0);
 617 
 618         // Setup Lighting
 619         gl.glShadeModel(gl.GL_SMOOTH());
 620         gl.glLightfv(gl.GL_LIGHT0(), gl.GL_POSITION(), pos.elementPointer());
 621         gl.glLightfv(gl.GL_LIGHT0(), gl.GL_AMBIENT(), spec.elementPointer());
 622         gl.glLightfv(gl.GL_LIGHT0(), gl.GL_DIFFUSE(), spec.elementPointer());
 623         gl.glLightfv(gl.GL_LIGHT0(), gl.GL_SPECULAR(), spec.elementPointer());
 624         gl.glMaterialfv(gl.GL_FRONT(), gl.GL_SHININESS(), shini.elementPointer());
 625         gl.glEnable(gl.GL_LIGHTING());
 626         gl.glEnable(gl.GL_LIGHT0());
 627         gl.glEnable(gl.GL_DEPTH_TEST());
 628     }
 629 
 630     void display() {
 631         gl.glClear(gl.GL_COLOR_BUFFER_BIT() | gl.GL_DEPTH_BUFFER_BIT());
 632         gl.glPushMatrix();
 633         gl.glRotatef(-20, 1, 1, 0);
 634         gl.glRotatef(rot, 0, 1, 0);
 635         glut.glutSolidTeapot(0.5);
 636         gl.glPopMatrix();
 637         glut.glutSwapBuffers();
 638     }
 639 
 640         void onIdle() {
 641         rot += 0.1;
 642         glut.glutPostRedisplay();
 643     }
 644 
 645     public static void main(String[] args) {
 646         try (Scope sc = Scope.newNativeScope()) {
 647             Pointer<Integer> argc = sc.allocate(NativeTypes.INT32);
 648             argc.set(0);
 649             glut.glutInit(argc, Pointer.nullPointer());
 650             glut.glutInitDisplayMode(glut.GLUT_DOUBLE() | glut.GLUT_RGBA() | glut.GLUT_DEPTH());
 651             glut.glutInitWindowSize(900, 900);
 652             glut.glutCreateWindow(sc.allocateCString("Hello Panama!"));
 653             Teapot teapot = new Teapot(sc);
 654             glut.glutDisplayFunc(sc.allocateCallback(teapot::display));
 655             glut.glutIdleFunc(sc.allocateCallback(teapot::onIdle));
 656             glut.glutMainLoop();
 657         }
 658     }
 659 }
 660 ```
 661 ### Running the Java code that uses OpenGL
 662 
 663 ```sh
 664 
 665 javac -cp opengl.jar Teapot.java
 666 
 667 java -cp opengl.jar:. Teapot
 668 
 669 ```
 670 
 671 
 672 ## Using TensorFlow C API (Mac OS)
 673 
 674 Quoted from [https://www.tensorflow.org/install/lang_c](https://www.tensorflow.org/install/lang_c)
 675 
 676 "TensorFlow provides a C API that can be used to build bindings for other
 677 languages. The API is defined in c_api.h and designed for simplicity and
 678 uniformity rather than convenience."
 679 
 680 
 681 ### Installing libtensorflow
 682 
 683 You can follow the setup procedure as described in the above page.
 684 
 685 Alternatively, on Mac, you can install libtensorflow using HomeBrew
 686 
 687 ```sh
 688 
 689 brew install libtensorflow
 690 
 691 ```
 692 
 693 Tensorflow ship the libtensorflow with an .so extension, this doesn't work
 694 well for java on MacOS as java expect .dylib extension. To work around this,
 695 create a symbolic link.
 696 
 697 ```sh
 698 
 699 sudo ln -s /usr/local/lib/libtensorflow.so /usr/local/lib/libtensorflow.dylib
 700 
 701 ```
 702 
 703 ### jextracting libtensorflow c_api.h
 704 
 705 The following command can be used to extract c_api.h.
 706 
 707 ```sh
 708 
 709 jextract -C -x -C c++  \
 710         -L /usr/local/lib -l tensorflow -infer-rpath \
 711         -o tf.jar -t org.tensorflow.panama \
 712         /usr/local/include/tensorflow/c/c_api.h
 713 
 714 ```
 715 
 716 The caveat to extract tensorflow C API is that it declare function prototype
 717 without argument in C++ style, for example, TF_Version(), which is considered
 718 incomplete C function prototype instead of C style as in TF_Version(void). An
 719 incomplete function prototype will become vararg funciton. To avoid that, we
 720 need to pass clang '-x c++' options to jextract with '-C -x -C c++'
 721 
 722 
 723 ### Java sample code that uses tensorflow library
 724 
 725 ```java
 726 
 727 import java.foreign.NativeTypes;
 728 import java.foreign.Scope;
 729 import java.foreign.memory.Array;
 730 import java.foreign.memory.LayoutType;
 731 import java.foreign.memory.Pointer;
 732 import org.tensorflow.panama.c_api.TF_DataType;
 733 import org.tensorflow.panama.c_api.TF_Graph;
 734 import org.tensorflow.panama.c_api.TF_Operation;
 735 import org.tensorflow.panama.c_api.TF_OperationDescription;
 736 import org.tensorflow.panama.c_api.TF_Output;
 737 import org.tensorflow.panama.c_api.TF_Session;
 738 import org.tensorflow.panama.c_api.TF_SessionOptions;
 739 import org.tensorflow.panama.c_api.TF_Status;
 740 import org.tensorflow.panama.c_api.TF_Tensor;
 741 
 742 import static org.tensorflow.panama.c_api_h.*;
 743 
 744 public class TensorFlowExample {
 745     static Pointer<TF_Operation> PlaceHolder(Pointer<TF_Graph> graph, Pointer<TF_Status> status,
 746                                       @TF_DataType int dtype, String name) {
 747         try (var s = Scope.newNativeScope()) {
 748             Pointer<TF_OperationDescription> desc = TF_NewOperation(graph,
 749                     s.allocateCString("Placeholder"), s.allocateCString(name));
 750             TF_SetAttrType(desc, s.allocateCString("dtype"), TF_FLOAT);
 751             return TF_FinishOperation(desc, status);
 752         }
 753     }
 754 
 755     static Pointer<TF_Operation> ConstValue(Pointer<TF_Graph> graph, Pointer<TF_Status> status,
 756                                 Pointer<TF_Tensor> tensor, String name) {
 757         try (var s = Scope.newNativeScope()) {
 758             Pointer<TF_OperationDescription> desc = TF_NewOperation(graph,
 759                     s.allocateCString("Const"), s.allocateCString(name));
 760             TF_SetAttrTensor(desc, s.allocateCString("value"), tensor, status);
 761             TF_SetAttrType(desc, s.allocateCString("dtype"), TF_TensorType(tensor));
 762             return TF_FinishOperation(desc, status);
 763         }
 764     }
 765 
 766     static Pointer<TF_Operation> Add(Pointer<TF_Graph> graph, Pointer<TF_Status> status,
 767                               Pointer<TF_Operation> one, Pointer<TF_Operation> two,
 768                               String name) {
 769         try (var s = Scope.newNativeScope()) {
 770             Pointer<TF_OperationDescription> desc = TF_NewOperation(graph,
 771                     s.allocateCString("AddN"), s.allocateCString(name));
 772             Array<TF_Output> add_inputs = s.allocateArray(
 773                     LayoutType.ofStruct(TF_Output.class),2);
 774             add_inputs.get(0).oper$set(one);
 775             add_inputs.get(0).index$set(0);
 776             add_inputs.get(1).oper$set(two);
 777             add_inputs.get(1).index$set(0);
 778             TF_AddInputList(desc, add_inputs.elementPointer(), 2);
 779             return TF_FinishOperation(desc, status);
 780         }
 781     }
 782 
 783     public static void main(String... args) {
 784         System.out.println("TensorFlow C library version: " + Pointer.toString(TF_Version()));
 785 
 786         Pointer<TF_Graph> graph = TF_NewGraph();
 787         Pointer<TF_SessionOptions> options = TF_NewSessionOptions();
 788         Pointer<TF_Status> status = TF_NewStatus();
 789         Pointer<TF_Session> session = TF_NewSession(graph, options, status);
 790 
 791         float in_val_one = 4.0f;
 792         float const_two = 2.0f;
 793 
 794         Pointer<TF_Tensor> tensor_in = TF_AllocateTensor(TF_FLOAT, Pointer.nullPointer(), 0, Float.BYTES);
 795         TF_TensorData(tensor_in).cast(NativeTypes.FLOAT).set(in_val_one);
 796         Pointer<TF_Tensor> tensor_const_two = TF_AllocateTensor(TF_FLOAT, Pointer.nullPointer(), 0, Float.BYTES);
 797         TF_TensorData(tensor_const_two).cast(NativeTypes.FLOAT).set(const_two);
 798 
 799         // Operations
 800         Pointer<TF_Operation> feed = PlaceHolder(graph, status, TF_FLOAT, "feed");
 801         Pointer<TF_Operation> two = ConstValue(graph, status, tensor_const_two, "const");
 802         Pointer<TF_Operation> add = Add(graph, status, feed, two, "add");
 803 
 804 
 805         try (var s = Scope.newNativeScope()) {
 806             var ltPtrTensor = LayoutType.ofStruct(TF_Tensor.class).pointer();
 807 
 808             // Session Inputs
 809             TF_Output input_operations = s.allocateStruct(TF_Output.class);
 810             input_operations.oper$set(feed);
 811             input_operations.index$set(0);
 812             Pointer<Pointer<TF_Tensor>> input_tensors = s.allocate(ltPtrTensor);
 813             input_tensors.set(tensor_in);
 814 
 815             // Session Outputs
 816             TF_Output output_operations = s.allocateStruct(TF_Output.class);
 817             output_operations.oper$set(add);
 818             output_operations.index$set(0);
 819             Pointer<Pointer<TF_Tensor>> output_tensors = s.allocate(ltPtrTensor);
 820             TF_SessionRun(session, Pointer.nullPointer(),
 821                 // Inputs
 822                 input_operations.ptr(), input_tensors, 1,
 823                 // Outputs
 824                 output_operations.ptr(), output_tensors, 1,
 825                 // Target operations
 826                 Pointer.nullPointer(), 0, Pointer.nullPointer(),
 827                 status);
 828 
 829             System.out.println(String.format("Session Run Status: %d - %s",
 830                     TF_GetCode(status), Pointer.toString(TF_Message(status))));
 831             Pointer<TF_Tensor> tensor_out = output_tensors.get();
 832             System.out.println("Output Tensor Type: " + TF_TensorType(tensor_out));
 833             float outval = TF_TensorData(tensor_out).cast(NativeTypes.FLOAT).get();
 834             System.out.println("Output Tensor Value: " + outval);
 835 
 836             TF_CloseSession(session, status);
 837             TF_DeleteSession(session, status);
 838 
 839             TF_DeleteSessionOptions(options);
 840 
 841             TF_DeleteGraph(graph);
 842 
 843             TF_DeleteTensor(tensor_in);
 844             TF_DeleteTensor(tensor_out);
 845             TF_DeleteTensor(tensor_const_two);
 846 
 847             TF_DeleteStatus(status);
 848         }
 849     }
 850 }
 851 
 852 ```
 853 
 854 ### Compiling and running the above TensorFlow sample
 855 
 856 ```sh
 857 
 858 javac -cp tf.jar TensorFlowExample.java
 859 
 860 java -cp tf.jar:. TensorFlowExample
 861 
 862 ```