1 % Using Panama "foreign" JDK 2 3 <?xml version="1.0" encoding="utf-8"?> 4 5 # Using Panama "foreign" JDK 6 7 There are two ways to get a panama foreign branch JDK. 8 9 1. Locally build "foreign" branch of panama repo [http://hg.openjdk.java.net/panama/dev/](http://hg.openjdk.java.net/panama/dev/) 10 2. Download pre-built panama "foreign" early access binaries from [http://jdk.java.net/panama/](http://jdk.java.net/panama/) 11 12 Using foreign function call in Java involves the following three steps: 13 14 1. Use **jextract** tool to generate java interface for your C header file(s) 15 2. Use **java.foreign** API to create ("bind") implementation for C header interfaces 16 3. Invoke C functions via the jextracted Java interface 17 18 ### Windows notes 19 20 You will (almost always) need to have Visual Studio installed, since most libraries indirectly depend on Visual Studio runtime libraries and this currently means that jextract needs their header to extract successfully. Windows examples have been tested with [Build Tools for Visual Studio 2017](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2017). 21 22 It is generally a good idea to give jextract a bunch of extra memory since a lot of big system headers are transitively included. The extra memory will make the jextract run significantly faster. Windows support was added only recently, and the memory usage of jextract has not been optimized yet, so this is a workaround. You can give extra memory by passing e.g. `-J-Xmx8G` to jextract as an additional argument, which in this example gives jextract 8 gigabytes of memory. 23 24 Commands are tested in PowerShell. 25 26 ## Embedding Python interpreter in your Java program (Mac OS) 27 28 ### jextract a Jar file for Python.h 29 30 ```sh 31 32 jextract -l python2.7 \ 33 -L /System/Library/Frameworks/Python.framework/Versions/2.7/lib --record-library-path \ 34 --exclude-symbols .*_FromFormatV\|_.*\|PyOS_vsnprintf\|.*_VaParse.*\|.*_VaBuild.*\|PyBuffer_SizeFromFormat\|vasprintf\|vfprintf\|vprintf\|vsprintf \ 35 -t org.python \ 36 /usr/include/python2.7/Python.h \ 37 -o python.jar 38 39 ``` 40 41 ### Java program that uses extracted Python interface 42 43 ```java 44 45 // import java.foreign packages 46 import java.foreign.Libraries; 47 import java.foreign.Scope; 48 import java.foreign.memory.Pointer; 49 50 // import jextracted python 'header' classes 51 import static org.python.Python_lib.*; 52 import static org.python.pythonrun_lib.*; 53 54 public class PythonMain { 55 public static void main(String[] args) { 56 Py_Initialize(); 57 try (Scope s = org.python.Python_lib.scope().fork()) { 58 PyRun_SimpleStringFlags(s.allocateCString( 59 "print(sum([33, 55, 66])); print('Hello from Python!')\n"), 60 Pointer.ofNull()); 61 } 62 Py_Finalize(); 63 } 64 } 65 66 ``` 67 68 ### Running the Java code that calls Python interpreter 69 70 ```sh 71 72 javac -cp python.jar PythonMain.java 73 74 java -cp python.jar:. PythonMain 75 76 ``` 77 78 ## jlinking Python Interpreter in your JDK (Mac OS) 79 80 ### Generating jmod using jextract 81 82 ```sh 83 84 jextract -l python2.7 \ 85 -L /System/Library/Frameworks/Python.framework/Versions/2.7/lib \ 86 --exclude-symbols .*_FromFormatV\|_.*\|PyOS_vsnprintf\|.*_VaParse.*\|.*_VaBuild.*\|PyBuffer_SizeFromFormat\|vasprintf\|vfprintf\|vprintf\|vsprintf \ 87 -t org.python \ 88 /usr/include/python2.7/Python.h \ 89 -o org.python.jmod 90 91 ``` 92 93 ### Jlinking python module to create a JDK with Python in it 94 95 jdk.compiler and org.python modules are added to the generated (jlinked) JDK 96 97 ```sh 98 99 jlink --add-modules org.python,jdk.compiler --module-path . --output pythonjdk 100 101 ``` 102 103 ### Compile and run user code with "pythonjdk" jdk 104 105 In the following commands, it is assumed that you've put $pythonjdk/bin in your $PATH 106 107 ```sh 108 109 javac PythonMain.java 110 java PythonMain 111 112 ``` 113 114 ## Embedding Python interpreter in your Java program (Ubuntu 16.04) 115 116 ### jextract a Jar file for Python.h 117 118 ```sh 119 120 jextract -l python2.7 \ 121 -L /usr/lib/python2.7/config-x86_64-linux-gnu --record-library-path \ 122 --exclude-symbols .*_FromFormatV\|_.*\|PyOS_vsnprintf\|.*_VaParse.*\|.*_VaBuild.*\|PyBuffer_SizeFromFormat\|vasprintf\|vfprintf\|vprintf\|vsprintf \ 123 -t org.python \ 124 /usr/include/python2.7/Python.h \ 125 -o python.jar 126 127 ``` 128 129 ### Compiling and Running Python Java example 130 131 Follow the instructions from the Mac OS section 132 133 ## Embedding Python interpreter in your Java program (Windows) 134 135 ### jextract a Jar file for Python.h 136 137 Where python 2.7 is installed in the `C:\Python27` directory: 138 139 ```powershell 140 jextract -L "C:\Windows\System32" -l python27 -o python.jar -t "org.python" --record-library-path C:\Python27\include\Python.h 141 ``` 142 143 ### Compiling and Running Python Java example 144 145 ```powershell 146 javac -cp python.jar PythonMain.java 147 java -cp "python.jar;." PythonMain 148 ``` 149 150 ## Using sqlite3 library in your Java program (Mac OS) 151 152 ### jextract a jar file for sqlite3.h 153 154 ```sh 155 156 jextract /usr/include/sqlite3.h -t org.sqlite -lsqlite3 \ 157 -L /usr/lib --record-library-path \ 158 --exclude-symbols sqlite3_vmprintf \ 159 --exclude-symbols sqlite3_vsnprintf \ 160 -o sqlite3.jar 161 162 ``` 163 164 ### Java sample that uses sqlite3 library 165 166 ```java 167 168 import java.lang.invoke.*; 169 import java.foreign.*; 170 import java.foreign.memory.*; 171 import org.sqlite.sqlite3_h.*; 172 import static org.sqlite.sqlite3_lib.*; 173 174 public class SqliteMain { 175 public static void main(String[] args) throws Exception { 176 try (Scope scope = scope().fork()) { 177 // char* errMsg; 178 Pointer<Pointer<Byte>> errMsg = scope.allocate(NativeTypes.INT8.pointer()); 179 180 // sqlite3* db; 181 Pointer<Pointer<sqlite3>> db = scope.allocate(LayoutType.ofStruct(sqlite3.class).pointer()); 182 183 int rc = sqlite3_open(scope.allocateCString("employee.db"), db); 184 if (rc != 0) { 185 System.err.println("sqlite3_open failed: " + rc); 186 return; 187 } 188 189 // create a new table 190 Pointer<Byte> sql = scope.allocateCString( 191 "CREATE TABLE EMPLOYEE (" + 192 " ID INT PRIMARY KEY NOT NULL," + 193 " NAME TEXT NOT NULL," + 194 " SALARY REAL NOT NULL )" 195 ); 196 197 rc = sqlite3_exec(db.get(), sql, Callback.ofNull(), Pointer.ofNull(), errMsg); 198 199 if (rc != 0) { 200 System.err.println("sqlite3_exec failed: " + rc); 201 System.err.println("SQL error: " + Pointer.toString(errMsg.get())); 202 sqlite3_free(errMsg.get()); 203 } 204 205 // insert two rows 206 sql = scope.allocateCString( 207 "INSERT INTO EMPLOYEE (ID,NAME,SALARY) " + 208 "VALUES (134, 'Xyz', 200000.0); " + 209 "INSERT INTO EMPLOYEE (ID,NAME,SALARY) " + 210 "VALUES (333, 'Abc', 100000.0);" 211 ); 212 rc = sqlite3_exec(db.get(), sql, Callback.ofNull(), Pointer.ofNull(), errMsg); 213 214 if (rc != 0) { 215 System.err.println("sqlite3_exec failed: " + rc); 216 System.err.println("SQL error: " + Pointer.toString(errMsg.get())); 217 sqlite3_free(errMsg.get()); 218 } 219 220 int[] rowNum = new int[1]; 221 // callback to print rows from SELECT query 222 Callback<FI1> callback = scope.allocateCallback(FI1.class, (a, argc, argv, columnNames) -> { 223 System.out.println("Row num: " + rowNum[0]++); 224 System.out.println("numColumns = " + argc); 225 for (int i = 0; i < argc; i++) { 226 String name = Pointer.toString(columnNames.offset(i).get()); 227 String value = Pointer.toString(argv.offset(i).get()); 228 System.out.printf("%s = %s\n", name, value); 229 } 230 return 0; 231 }); 232 233 // select query 234 sql = scope.allocateCString("SELECT * FROM EMPLOYEE"); 235 rc = sqlite3_exec(db.get(), sql, callback, Pointer.ofNull(), errMsg); 236 237 if (rc != 0) { 238 System.err.println("sqlite3_exec failed: " + rc); 239 System.err.println("SQL error: " + Pointer.toString(errMsg.get())); 240 sqlite3_free(errMsg.get()); 241 } 242 243 sqlite3_close(db.get()); 244 } 245 } 246 } 247 248 ``` 249 250 ### Compiling and Running sqlite Java example 251 252 ```sh 253 254 javac -cp sqlite3.jar SqlMain.java 255 java -cp sqlite3.jar:. SqlMain 256 257 ``` 258 259 ## Using sqlite3 library in your Java program (Ubuntu 16.04) 260 261 ### Installing sqlite3 262 263 On Ubuntu (16.04) to install sqlite3 headers and libraries the following command is required: 264 265 ```sh 266 sudo apt-get install libsqlite3-dev 267 ``` 268 269 This should install the sqlite3 header (under `/usr/include`), as well as the sqlite3 shared library (under `/usr/lib/x86_64-linux-gnu`). 270 271 ### jextract a jar file for sqlite3.h 272 273 To extract sqlite, run the following command: 274 275 ```sh 276 jextract /usr/include/sqlite3.h -t org.sqlite -lsqlite3 \ 277 -L /usr/lib/x86_64-linux-gnu --record-library-path \ 278 --exclude-symbols sqlite3_vmprintf \ 279 --exclude-symbols sqlite3_vsnprintf \ 280 -o sqlite3.jar 281 ``` 282 283 ### Compiling and Running sqlite Java example 284 285 Please refer to the Mac OS instructions; once the library as been extracted (as per the instructions above), the sample program shown in that section should work on Ubuntu as well. 286 287 ## Using BLAS library 288 289 BLAS is a popular library that allows fast matrix and vector computation: [http://www.netlib.org/blas/](http://www.netlib.org/blas/). 290 291 ### Installing OpenBLAS (Mac OS) 292 293 On Mac, blas is available as part of the OpenBLAS library: [https://github.com/xianyi/OpenBLAS/wiki](https://github.com/xianyi/OpenBLAS/wiki) 294 295 OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version. 296 297 You can install openblas using HomeBrew 298 299 ```sh 300 301 brew install openblas 302 303 ``` 304 305 It installs include and lib directories under /usr/local/opt/openblas 306 307 ### Installing OpenBLAS (Ubuntu 16.04) 308 309 On Ubuntu, blas is distributed as part of the atlas library: [http://math-atlas.sourceforge.net/](http://math-atlas.sourceforge.net/). 310 311 You can install atlas using apt 312 313 ```sh 314 315 sudo apt-get install libatlas-base-dev 316 317 ``` 318 319 This command will install include files under `/usr/include/atlas` and corresponding libraries under `/usr/lib/atlas-dev`. 320 321 322 ### jextracting cblas.h (MacOS) 323 324 The following command can be used to extract cblas.h on MacOs 325 326 ```sh 327 328 jextract -C "-D FORCE_OPENBLAS_COMPLEX_STRUCT" \ 329 -L /usr/local/opt/openblas/lib -I /usr/local/opt/openblas \ 330 -l openblas -t blas --record-library-path /usr/local/opt/openblas/include/cblas.h \ 331 -o cblas.jar 332 333 ``` 334 335 The FORCE_OPENBLAS_COMPLEX_STRUCT define is needed because jextract does not 336 yet handle C99 `_Complex` types. The rest of the options are standard ones. 337 338 ### jextracting cblas.h (Ubuntu 16.04) 339 340 The following command can be used to extract cblas.h on Ubuntu 341 342 ```sh 343 344 jextract -L /usr/lib/atlas-base -I /usr/include/atlas/ \ 345 -l cblas -t blas --record-library-path \ 346 /usr/include/atlas/cblas.h -o cblas.jar 347 348 ``` 349 350 ### Java sample code that uses cblas library 351 352 ```java 353 354 import blas.cblas; 355 356 import static blas.cblas_lib.*; 357 import static blas.cblas_lib.CBLAS_ORDER.*; 358 import static blas.cblas_lib.CBLAS_TRANSPOSE.*; 359 360 import java.foreign.NativeTypes; 361 import java.foreign.Scope; 362 import java.foreign.memory.Array; 363 364 public class TestBlas { 365 public static void main(String[] args) { 366 @blas.cblas_h.CBLAS_ORDER int Layout; 367 @blas.cblas_h.CBLAS_TRANSPOSE int transa; 368 369 double alpha, beta; 370 int m, n, lda, incx, incy, i; 371 372 Layout = CblasColMajor; 373 transa = CblasNoTrans; 374 375 m = 4; /* Size of Column ( the number of rows ) */ 376 n = 4; /* Size of Row ( the number of columns ) */ 377 lda = 4; /* Leading dimension of 5 * 4 matrix is 5 */ 378 incx = 1; 379 incy = 1; 380 alpha = 1; 381 beta = 0; 382 383 try (Scope sc = scope().fork()){ 384 Array<Double> a = sc.allocateArray(NativeTypes.DOUBLE, m * n); 385 Array<Double> x = sc.allocateArray(NativeTypes.DOUBLE, n); 386 Array<Double> y = sc.allocateArray(NativeTypes.DOUBLE, n); 387 /* The elements of the first column */ 388 a.set(0, 1.0); 389 a.set(1, 2.0); 390 a.set(2, 3.0); 391 a.set(3, 4.0); 392 /* The elements of the second column */ 393 a.set(m, 1.0); 394 a.set(m + 1, 1.0); 395 a.set(m + 2, 1.0); 396 a.set(m + 3, 1.0); 397 /* The elements of the third column */ 398 a.set(m * 2, 3.0); 399 a.set(m * 2 + 1, 4.0); 400 a.set(m * 2 + 2, 5.0); 401 a.set(m * 2 + 3, 6.0); 402 /* The elements of the fourth column */ 403 a.set(m * 3, 5.0); 404 a.set(m * 3 + 1, 6.0); 405 a.set(m * 3 + 2, 7.0); 406 a.set(m * 3 + 3, 8.0); 407 /* The elemetns of x and y */ 408 x.set(0, 1.0); 409 x.set(1, 2.0); 410 x.set(2, 1.0); 411 x.set(3, 1.0); 412 y.set(0, 0.0); 413 y.set(1, 0.0); 414 y.set(2, 0.0); 415 y.set(3, 0.0); 416 417 cblas_dgemv(Layout, transa, m, n, alpha, a.elementPointer(), lda, x.elementPointer(), incx, beta, 418 y.elementPointer(), incy); 419 /* Print y */ 420 for (i = 0; i < n; i++) 421 System.out.print(String.format(" y%d = %f\n", i, y.get(i))); 422 } 423 } 424 } 425 426 ``` 427 428 ### Compiling and running the above cblas samples 429 430 ```sh 431 432 javac -cp cblas.jar TestBlas.java 433 434 java -cp cblas.jar:. TestBlas 435 436 ``` 437 438 ## Using LAPACK library (Ubuntu) 439 440 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. 441 442 ### jextracting clapack.h (Ubuntu 16.04) 443 444 The following command can be used to extract the LAPACK header: 445 446 ```sh 447 448 jextract -L /usr/lib/atlas-base/atlas -I /usr/include/atlas/ \ 449 -l lapack -t lapack --record-library-path /usr/include/atlas/clapack.h -o clapack.jar 450 451 ``` 452 453 ### Java sample code that uses LAPACK library 454 455 ```java 456 import java.foreign.NativeTypes; 457 import java.foreign.Scope; 458 import java.foreign.memory.Array; 459 460 import static lapack.clapack_lib.*; 461 import static lapack.cblas_lib.*; 462 463 public class TestLapack { 464 public static void main(String[] args) { 465 466 /* Locals */ 467 try (Scope sc = lapack.clapack_lib.scope().fork()) { 468 Array<Double> A = sc.allocateArray(NativeTypes.DOUBLE, new double[]{ 469 1, 2, 3, 4, 5, 1, 3, 5, 2, 4, 1, 4, 2, 5, 3 470 }); 471 Array<Double> b = sc.allocateArray(NativeTypes.DOUBLE, new double[]{ 472 -10, 12, 14, 16, 18, -3, 14, 12, 16, 16 473 }); 474 int info, m, n, lda, ldb, nrhs; 475 476 /* Initialization */ 477 m = 5; 478 n = 3; 479 nrhs = 2; 480 lda = 5; 481 ldb = 5; 482 483 /* Print Entry Matrix */ 484 print_matrix_colmajor("Entry Matrix A", m, n, A, lda ); 485 /* Print Right Rand Side */ 486 print_matrix_colmajor("Right Hand Side b", n, nrhs, b, ldb ); 487 System.out.println(); 488 489 /* Executable statements */ 490 // printf( "LAPACKE_dgels (col-major, high-level) Example Program Results\n" ); 491 /* Solve least squares problem*/ 492 info = clapack_dgels(CblasColMajor, CblasNoTrans, m, n, nrhs, A.elementPointer(), lda, b.elementPointer(), ldb); 493 494 /* Print Solution */ 495 print_matrix_colmajor("Solution", n, nrhs, b, ldb ); 496 System.out.println(); 497 System.exit(info); 498 } 499 } 500 501 static void print_matrix_colmajor(String msg, int m, int n, Array<Double> mat, int ldm) { 502 int i, j; 503 System.out.printf("\n %s\n", msg); 504 505 for( i = 0; i < m; i++ ) { 506 for( j = 0; j < n; j++ ) System.out.printf(" %6.2f", mat.get(i+j*ldm)); 507 System.out.printf( "\n" ); 508 } 509 } 510 } 511 ``` 512 513 ### Compiling and running the above LAPACK sample 514 515 ```sh 516 517 javac -cp clapack.jar TestLapack.java 518 519 java -cp clapack.jar:. TestLapack 520 521 ``` 522 523 ## Using LAPACK library (Mac OS) 524 525 On Mac OS, lapack is installed under /usr/local/opt/lapack directory. 526 527 ### jextracting lapacke.h 528 529 ```sh 530 531 jextract -L /usr/local/opt/lapack/lib -I /usr/local/opt/lapack/ \ 532 -l lapacke -t lapack --record-library-path /usr/local/opt/lapack/include/lapacke.h -o clapack.jar 533 534 ``` 535 ### Java sample code that uses LAPACK library 536 537 ```java 538 539 import java.foreign.NativeTypes; 540 import java.foreign.Scope; 541 import java.foreign.memory.Array; 542 543 import static lapack.lapacke_lib.*; 544 545 public class TestLapack { 546 public static void main(String[] args) { 547 548 /* Locals */ 549 try (Scope sc = scope().fork()) { 550 Array<Double> A = sc.allocateArray(NativeTypes.DOUBLE, new double[]{ 551 1, 2, 3, 4, 5, 1, 3, 5, 2, 4, 1, 4, 2, 5, 3 552 }); 553 Array<Double> b = sc.allocateArray(NativeTypes.DOUBLE, new double[]{ 554 -10, 12, 14, 16, 18, -3, 14, 12, 16, 16 555 }); 556 int info, m, n, lda, ldb, nrhs; 557 558 /* Initialization */ 559 m = 5; 560 n = 3; 561 nrhs = 2; 562 lda = 5; 563 ldb = 5; 564 565 /* Print Entry Matrix */ 566 print_matrix_colmajor("Entry Matrix A", m, n, A, lda ); 567 /* Print Right Rand Side */ 568 print_matrix_colmajor("Right Hand Side b", n, nrhs, b, ldb ); 569 System.out.println(); 570 571 /* Executable statements */ 572 // printf( "LAPACKE_dgels (col-major, high-level) Example Program Results\n" ); 573 /* Solve least squares problem*/ 574 info = LAPACKE_dgels(LAPACK_COL_MAJOR, (byte)'N', m, n, nrhs, A.elementPointer(), lda, b.elementPointer(), ldb); 575 576 /* Print Solution */ 577 print_matrix_colmajor("Solution", n, nrhs, b, ldb ); 578 System.out.println(); 579 System.exit(info); 580 } 581 } 582 583 static void print_matrix_colmajor(String msg, int m, int n, Array<Double> mat, int ldm) { 584 int i, j; 585 System.out.printf("\n %s\n", msg); 586 587 for( i = 0; i < m; i++ ) { 588 for( j = 0; j < n; j++ ) System.out.printf(" %6.2f", mat.get(i+j*ldm)); 589 System.out.printf( "\n" ); 590 } 591 } 592 } 593 594 ``` 595 596 ### Compiling and running the above LAPACK sample 597 598 ```sh 599 600 javac -cp clapack.jar TestLapack.java 601 602 java -cp clapack.jar:. TestLapack 603 604 ``` 605 606 ## Using libproc library to list processes from Java (Mac OS) 607 608 ### jextract a jar file for libproc.h 609 610 jextract -t org.unix -lproc -L /usr/lib --record-library-path -o libproc.jar /usr/include/libproc.h 611 612 ### Java program that uses libproc to list processes 613 614 ```java 615 616 import java.foreign.*; 617 import java.foreign.memory.*; 618 import static org.unix.libproc_lib.*; 619 620 public class LibprocMain { 621 private static final int NAME_BUF_MAX = 256; 622 623 public static void main(String[] args) { 624 // Scope for native allocations 625 try (Scope s = scope().fork()) { 626 // get the number of processes 627 int numPids = proc_listallpids(Pointer.ofNull(), 0); 628 // allocate an array 629 Array<Integer> pids = s.allocateArray(NativeTypes.INT32, numPids); 630 // list all the pids into the native array 631 proc_listallpids(pids.elementPointer(), numPids); 632 // convert native array to java array 633 int[] jpids = pids.toArray(num -> new int[num]); 634 // buffer for process name 635 Pointer<Byte> nameBuf = s.allocate(NativeTypes.INT8, NAME_BUF_MAX); 636 for (int i = 0; i < jpids.length; i++) { 637 int pid = jpids[i]; 638 // get the process name 639 proc_name(pid, nameBuf, NAME_BUF_MAX); 640 String procName = Pointer.toString(nameBuf); 641 // print pid and process name 642 System.out.printf("%d %s\n", pid, procName); 643 } 644 } 645 } 646 } 647 648 ``` 649 650 ### Running the Java code that uses libproc 651 652 ```sh 653 654 javac -cp libproc.jar LibprocMain.java 655 656 java -cp libproc.jar:. LibprocMain 657 658 ``` 659 660 ## Using readline library from Java code (Mac OS) 661 662 ### jextract a jar file for readline.h 663 664 ```sh 665 666 jextract -l readline -L /usr/local/opt/readline/lib/ --record-library-path \ 667 -t org.unix \ 668 /usr/include/readline/readline.h \ 669 --exclude-symbol readline_echoing_p -o readline.jar 670 671 ``` 672 673 ### Java code that uses readline 674 675 ```java 676 677 import java.foreign.*; 678 import java.foreign.memory.*; 679 import static org.unix.readline_lib.*; 680 681 public class Readline { 682 public static void main(String[] args) { 683 // Scope for native allocations 684 try (Scope s = scope().fork()) { 685 // allocate C memory initialized with Java string content 686 var pstr = s.allocateCString("name? "); 687 688 // call "readline" API 689 var p = readline(pstr); 690 691 // print char* as is 692 System.out.println(p); 693 // convert char* ptr from readline as Java String & print it 694 System.out.println(Pointer.toString(p)); 695 } 696 } 697 } 698 699 ``` 700 701 ### Running the java code that uses readline 702 703 ``` 704 705 javac -cp readline.jar Readline.java 706 707 java -cp readline.jar:. Readline 708 709 ``` 710 711 ## Using libcurl from Java (Mac OS) 712 713 ### jextract a jar for curl.h 714 715 ```sh 716 717 jextract -t org.unix -L /usr/lib -lcurl --record-library-path /usr/include/curl/curl.h -o curl.jar 718 719 ``` 720 721 ### Java code that uses libcurl 722 723 ```java 724 725 import java.lang.invoke.*; 726 import java.foreign.*; 727 import java.foreign.memory.*; 728 import org.unix.curl_lib; 729 import static org.unix.curl_lib.*; 730 import static org.unix.easy_lib.*; 731 732 public class CurlMain { 733 public static void main(String[] args) { 734 try (Scope s = curl_lib.scope().fork()) { 735 curl_global_init(CURL_GLOBAL_DEFAULT); 736 Pointer<Void> curl = curl_easy_init(); 737 if(!curl.isNull()) { 738 Pointer<Byte> url = s.allocateCString(args[0]); 739 curl_easy_setopt(curl, CURLOPT_URL, url); 740 int res = curl_easy_perform(curl); 741 if (res != CURLE_OK) { 742 curl_easy_cleanup(curl); 743 } 744 } 745 curl_global_cleanup(); 746 } 747 } 748 } 749 750 ``` 751 752 ### Running the java code that uses libcurl 753 754 ```sh 755 756 javac -cp curl.jar CurlMain.java 757 java -cp curl.jar:. CurlMain <url> 758 759 ``` 760 761 ## Using unistd.h from Java code (Linux) 762 763 ### jextract a jar file for unistd.h 764 765 ```sh 766 767 jextract /usr/include/unistd.h -t org.unix -o unistd.jar 768 769 ``` 770 771 ### Java code that calls getpid 772 773 ```java 774 775 import java.foreign.*; 776 import java.lang.invoke.*; 777 import org.unix.unistd_h; 778 779 780 public class Getpid { 781 public static void main(String[] args) { 782 // bind unistd interface 783 var u = Libraries.bind(MethodHandles.lookup(), unistd_h.class); 784 // call getpid from the unistd.h 785 System.out.println(u.getpid()); 786 // check process id from Java API! 787 System.out.println(ProcessHandle.current().pid()); 788 } 789 } 790 791 ``` 792 793 ### Running the Java code that uses getpid 794 795 ```sh 796 797 javac -cp unistd.jar Getpid.java 798 799 java -cp unistd.jar:. Getpid 800 801 ``` 802 803 804 ## Using OpenGL graphic library (Ubuntu 16.04) 805 806 OpenGL is a popular portable graphic library: [https://www.opengl.org/](https://www.opengl.org/) 807 808 ### Installing OpenGL (Ubuntu 16.04) 809 810 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. 811 812 OpenGL is always coupled with a bunch of other libraries, namely GLU and glut. You can install all those libraries using `apt`, as follows: 813 814 ```sh 815 816 sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev 817 818 ``` 819 820 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/`. 821 822 ### jextracting OpenGL (Ubuntu 16.04) 823 824 To extract the opengl libraries the following command suffices: 825 826 ```sh 827 828 jextract -L /usr/lib/x86_64-linux-gnu -l glut -l GLU -l GL --record-library-path -t opengl -o opengl.jar /usr/include/GL/glut.h 829 830 ``` 831 832 Since glut depends on the other libraries (GLU and GL), it is not necessary to give additional headers to jextract. 833 834 ### Java sample code that uses the OpenGL library 835 836 ```java 837 import java.foreign.NativeTypes; 838 import java.foreign.Scope; 839 import java.foreign.memory.Array; 840 import java.foreign.memory.Pointer; 841 842 import static opengl.gl_lib.*; 843 import static opengl.freeglut_std_lib.*; 844 845 public class Teapot { 846 847 float rot = 0; 848 849 Teapot(Scope sc) { 850 // Misc Parameters 851 Array<Float> pos = sc.allocateArray(NativeTypes.FLOAT, new float[] {0.0f, 15.0f, -15.0f, 0}); 852 Array<Float> spec = sc.allocateArray(NativeTypes.FLOAT, new float[] {1, 1, 1, 0}); 853 Array<Float> shini = sc.allocateArray(NativeTypes.FLOAT, new float[] {113}); 854 855 // Reset Background 856 glClearColor(0, 0, 0, 0); 857 858 // Setup Lighting 859 glShadeModel(GL_SMOOTH); 860 glLightfv(GL_LIGHT0, GL_POSITION, pos.elementPointer()); 861 glLightfv(GL_LIGHT0, GL_AMBIENT, spec.elementPointer()); 862 glLightfv(GL_LIGHT0, GL_DIFFUSE, spec.elementPointer()); 863 glLightfv(GL_LIGHT0, GL_SPECULAR, spec.elementPointer()); 864 glMaterialfv(GL_FRONT, GL_SHININESS, shini.elementPointer()); 865 glEnable(GL_LIGHTING); 866 glEnable(GL_LIGHT0); 867 glEnable(GL_DEPTH_TEST); 868 } 869 870 void display() { 871 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 872 glPushMatrix(); 873 glRotatef(-20, 1, 1, 0); 874 glRotatef(rot, 0, 1, 0); 875 glutSolidTeapot(0.5); 876 glPopMatrix(); 877 glutSwapBuffers(); 878 } 879 880 void onIdle() { 881 rot += 0.1; 882 glutPostRedisplay(); 883 } 884 885 public static void main(String[] args) { 886 try (Scope sc = opengl.gl_lib.scope().fork()) { 887 Pointer<Integer> argc = sc.allocate(NativeTypes.INT32); 888 argc.set(0); 889 glutInit(argc, Pointer.ofNull()); 890 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); 891 glutInitWindowSize(900, 900); 892 glutCreateWindow(sc.allocateCString("Hello Panama!")); 893 Teapot teapot = new Teapot(sc); 894 glutDisplayFunc(sc.allocateCallback(teapot::display)); 895 glutIdleFunc(sc.allocateCallback(teapot::onIdle)); 896 glutMainLoop(); 897 } 898 } 899 } 900 ``` 901 ### Running the Java code that uses OpenGL (Ubuntu 16.04) 902 903 ```sh 904 905 javac -cp opengl.jar Teapot.java 906 907 java -cp opengl.jar:. Teapot 908 909 ``` 910 911 ## Using OpenGL graphic library (Windows) 912 913 ### Installing OpenGL 914 915 Download the freeglut package for MSVC at [https://www.transmissionzero.co.uk/software/freeglut-devel/](https://www.transmissionzero.co.uk/software/freeglut-devel/) 916 917 Extract the freeglut zip. 918 919 ### jextracting OpenGL 920 921 Navigate to the root directory of the extracted zip and run the following commands: 922 923 ```powershell 924 $inc = "C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0" 925 jextract -L C:\Windows\System32\ -L .\freeglut\bin\x64\ -l opengl32 -l freeglut -t opengl -o opengl.jar --package-map "$inc\um\gl=opengl" --record-library-path .\freeglut\include\GL\glut.h 926 ``` 927 928 The directory that is assigned to `$inc` is an example, and is system dependent. Make sure that the build number at the end of the path (in this case `10.0.17134.0`) is the latest one found in the parent folder (`C:\Program Files (x86)\Windows Kits\10\Include\`). 929 930 There are a bunch of warnings generated, but as long as the jar file is generated in the working directory the extraction was successful. 931 932 ### Java sample code that uses the OpenGL library 933 934 This is the same as in the Ubuntu section 935 936 ### Running the Java code that uses OpenGL 937 938 ```powershell 939 javac -cp .\opengl.jar Teapot.java 940 java -cp "opengl.jar;." Teapot 941 ``` 942 943 ## Using TensorFlow C API (Mac OS) 944 945 Quoted from [https://www.tensorflow.org/install/lang_c](https://www.tensorflow.org/install/lang_c) 946 947 "TensorFlow provides a C API that can be used to build bindings for other 948 languages. The API is defined in c_api.h and designed for simplicity and 949 uniformity rather than convenience." 950 951 952 ### Installing libtensorflow 953 954 You can follow the setup procedure as described in the above page. 955 956 Alternatively, on Mac, you can install libtensorflow using HomeBrew 957 958 ```sh 959 960 brew install libtensorflow 961 962 ``` 963 964 Tensorflow ship the libtensorflow with an .so extension, this doesn't work 965 well for java on MacOS as java expect .dylib extension. To work around this, 966 create a symbolic link. 967 968 ```sh 969 970 sudo ln -s /usr/local/lib/libtensorflow.so /usr/local/lib/libtensorflow.dylib 971 972 ``` 973 974 ### jextracting libtensorflow c_api.h 975 976 The following command can be used to extract c_api.h. 977 978 ```sh 979 980 jextract -C -x -C c++ \ 981 -L /usr/local/lib -l tensorflow --record-library-path \ 982 -o tf.jar -t org.tensorflow.panama \ 983 /usr/local/include/tensorflow/c/c_api.h 984 985 ``` 986 987 The caveat to extract tensorflow C API is that it declare function prototype 988 without argument in C++ style, for example, TF_Version(), which is considered 989 incomplete C function prototype instead of C style as in TF_Version(void). An 990 incomplete function prototype will become vararg funciton. To avoid that, we 991 need to pass clang '-x c++' options to jextract with '-C -x -C c++' 992 993 ### Java sample code that uses tensorflow library 994 995 ```java 996 997 import java.foreign.NativeTypes; 998 import java.foreign.Scope; 999 import java.foreign.memory.Array; 1000 import java.foreign.memory.LayoutType; 1001 import java.foreign.memory.Pointer; 1002 import org.tensorflow.panama.c_api_h.TF_DataType; 1003 import org.tensorflow.panama.c_api_h.TF_Graph; 1004 import org.tensorflow.panama.c_api_h.TF_Operation; 1005 import org.tensorflow.panama.c_api_h.TF_OperationDescription; 1006 import org.tensorflow.panama.c_api_h.TF_Output; 1007 import org.tensorflow.panama.c_api_h.TF_Session; 1008 import org.tensorflow.panama.c_api_h.TF_SessionOptions; 1009 import org.tensorflow.panama.c_api_h.TF_Status; 1010 import org.tensorflow.panama.c_api_h.TF_Tensor; 1011 1012 import static org.tensorflow.panama.c_api_lib.*; 1013 import static org.tensorflow.panama.c_api_lib.TF_DataType.*; 1014 1015 public class TensorFlowExample { 1016 static Pointer<TF_Operation> PlaceHolder(Pointer<TF_Graph> graph, Pointer<TF_Status> status, 1017 @TF_DataType int dtype, String name) { 1018 try (var s = scope().fork()) { 1019 Pointer<TF_OperationDescription> desc = TF_NewOperation(graph, 1020 s.allocateCString("Placeholder"), s.allocateCString(name)); 1021 TF_SetAttrType(desc, s.allocateCString("dtype"), TF_FLOAT); 1022 return TF_FinishOperation(desc, status); 1023 } 1024 } 1025 1026 static Pointer<TF_Operation> ConstValue(Pointer<TF_Graph> graph, Pointer<TF_Status> status, 1027 Pointer<TF_Tensor> tensor, String name) { 1028 try (var s = scope().fork()) { 1029 Pointer<TF_OperationDescription> desc = TF_NewOperation(graph, 1030 s.allocateCString("Const"), s.allocateCString(name)); 1031 TF_SetAttrTensor(desc, s.allocateCString("value"), tensor, status); 1032 TF_SetAttrType(desc, s.allocateCString("dtype"), TF_TensorType(tensor)); 1033 return TF_FinishOperation(desc, status); 1034 } 1035 } 1036 1037 static Pointer<TF_Operation> Add(Pointer<TF_Graph> graph, Pointer<TF_Status> status, 1038 Pointer<TF_Operation> one, Pointer<TF_Operation> two, 1039 String name) { 1040 try (var s = scope().fork()) { 1041 Pointer<TF_OperationDescription> desc = TF_NewOperation(graph, 1042 s.allocateCString("AddN"), s.allocateCString(name)); 1043 Array<TF_Output> add_inputs = s.allocateArray( 1044 LayoutType.ofStruct(TF_Output.class),2); 1045 add_inputs.get(0).oper$set(one); 1046 add_inputs.get(0).index$set(0); 1047 add_inputs.get(1).oper$set(two); 1048 add_inputs.get(1).index$set(0); 1049 TF_AddInputList(desc, add_inputs.elementPointer(), 2); 1050 return TF_FinishOperation(desc, status); 1051 } 1052 } 1053 1054 public static void main(String... args) { 1055 System.out.println("TensorFlow C library version: " + Pointer.toString(TF_Version())); 1056 1057 Pointer<TF_Graph> graph = TF_NewGraph(); 1058 Pointer<TF_SessionOptions> options = TF_NewSessionOptions(); 1059 Pointer<TF_Status> status = TF_NewStatus(); 1060 Pointer<TF_Session> session = TF_NewSession(graph, options, status); 1061 1062 float in_val_one = 4.0f; 1063 float const_two = 2.0f; 1064 1065 Pointer<TF_Tensor> tensor_in = TF_AllocateTensor(TF_FLOAT, Pointer.ofNull(), 0, Float.BYTES); 1066 TF_TensorData(tensor_in).cast(NativeTypes.FLOAT).set(in_val_one); 1067 Pointer<TF_Tensor> tensor_const_two = TF_AllocateTensor(TF_FLOAT, Pointer.ofNull(), 0, Float.BYTES); 1068 TF_TensorData(tensor_const_two).cast(NativeTypes.FLOAT).set(const_two); 1069 1070 // Operations 1071 Pointer<TF_Operation> feed = PlaceHolder(graph, status, TF_FLOAT, "feed"); 1072 Pointer<TF_Operation> two = ConstValue(graph, status, tensor_const_two, "const"); 1073 Pointer<TF_Operation> add = Add(graph, status, feed, two, "add"); 1074 1075 1076 try (var s = scope().fork()) { 1077 var ltPtrTensor = LayoutType.ofStruct(TF_Tensor.class).pointer(); 1078 1079 // Session Inputs 1080 TF_Output input_operations = s.allocateStruct(TF_Output.class); 1081 input_operations.oper$set(feed); 1082 input_operations.index$set(0); 1083 Pointer<Pointer<TF_Tensor>> input_tensors = s.allocate(ltPtrTensor); 1084 input_tensors.set(tensor_in); 1085 1086 // Session Outputs 1087 TF_Output output_operations = s.allocateStruct(TF_Output.class); 1088 output_operations.oper$set(add); 1089 output_operations.index$set(0); 1090 Pointer<Pointer<TF_Tensor>> output_tensors = s.allocate(ltPtrTensor); 1091 TF_SessionRun(session, Pointer.ofNull(), 1092 // Inputs 1093 input_operations.ptr(), input_tensors, 1, 1094 // Outputs 1095 output_operations.ptr(), output_tensors, 1, 1096 // Target operations 1097 Pointer.ofNull(), 0, Pointer.ofNull(), 1098 status); 1099 1100 System.out.println(String.format("Session Run Status: %d - %s", 1101 TF_GetCode(status), Pointer.toString(TF_Message(status)))); 1102 Pointer<TF_Tensor> tensor_out = output_tensors.get(); 1103 System.out.println("Output Tensor Type: " + TF_TensorType(tensor_out)); 1104 float outval = TF_TensorData(tensor_out).cast(NativeTypes.FLOAT).get(); 1105 System.out.println("Output Tensor Value: " + outval); 1106 1107 TF_CloseSession(session, status); 1108 TF_DeleteSession(session, status); 1109 1110 TF_DeleteSessionOptions(options); 1111 1112 TF_DeleteGraph(graph); 1113 1114 TF_DeleteTensor(tensor_in); 1115 TF_DeleteTensor(tensor_out); 1116 TF_DeleteTensor(tensor_const_two); 1117 1118 TF_DeleteStatus(status); 1119 } 1120 } 1121 } 1122 1123 ``` 1124 1125 ### Compiling and running the above TensorFlow sample 1126 1127 ```sh 1128 1129 javac -cp tf.jar TensorFlowExample.java 1130 1131 java -cp tf.jar:. TensorFlowExample 1132 1133 ``` 1134 1135 ## Using TensorFlow C API (Windows) 1136 1137 ### Installing libtensorflow 1138 1139 You can download a binary distribution from [https://www.tensorflow.org/install/lang_c](https://www.tensorflow.org/install/lang_c) 1140 1141 Extract the zip file. 1142 1143 ### jextracting libtensorflow c_api.h 1144 1145 The problem outlined in the Mac OS instruction w.r.t. incorrect function prototypes still exists (though it has been solved in the Tensorflow github repository, this change has not yet made it into the binary distributions). On Windows there is however no jextract command that works around this, so the only way to extract the \include\tensorflow\c\c_api.h header successfully is to first manually fix the incorrect function prototypes: 1146 1147 ```C 1148 TF_Version() -> TF_Version(void) 1149 TF_NewGraph() -> TF_NewGraph(void) 1150 TF_NewSessionOptions() -> TF_NewSessionOptions(void) 1151 TF_NewStatus() -> TF_NewStatus(void) 1152 TF_NewBuffer() -> TF_NewBuffer(void) 1153 TF_NewImportGraphDefOptions() -> TF_NewImportGraphDefOptions(void) 1154 TF_GetAllOpList() -> TF_GetAllOpList(void) 1155 ``` 1156 Once you've done this you can use the following jextract command from the libtensorflow root directory: 1157 1158 ```powershell 1159 jextract -L .\lib -l tensorflow -o tf.jar -t "org.tensorflow.panama" --record-library-path .\include\tensorflow\c\c_api.h 1160 ``` 1161 1162 ### Java sample code that uses tensorflow library 1163 1164 This is the same as for the Mac OS section. 1165 1166 ### Compiling and running the above TensorFlow sample 1167 1168 ```powershell 1169 javac -cp tf.jar TensorFlowExample.java 1170 java -cp "tf.jar;." TensorFlowExample 1171 ```