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_h.*; 52 import static org.python.pythonrun_h.*; 53 54 public class PythonMain { 55 public static void main(String[] args) { 56 Py_Initialize(); 57 try (Scope s = org.python.Python_h.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.*; 172 import static org.sqlite.sqlite3_h.*; 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_h.*; 357 import static blas.cblas_h.CBLAS_ORDER.*; 358 import static blas.cblas_h.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 @cblas.CBLAS_ORDER int Layout; 367 @cblas.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_h.*; 461 import static lapack.cblas_h.*; 462 463 public class TestLapack { 464 public static void main(String[] args) { 465 466 /* Locals */ 467 try (Scope sc = lapack.clapack_h.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_h.*; 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_h.*; 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_h.*; 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.*; 729 import org.unix.curl_h; 730 import static org.unix.curl_h.*; 731 import static org.unix.easy_h.*; 732 733 public class CurlMain { 734 public static void main(String[] args) { 735 try (Scope s = curl_h.scope().fork()) { 736 curl_global_init(CURL_GLOBAL_DEFAULT); 737 Pointer<Void> curl = curl_easy_init(); 738 if(!curl.isNull()) { 739 Pointer<Byte> url = s.allocateCString(args[0]); 740 curl_easy_setopt(curl, CURLOPT_URL, url); 741 int res = curl_easy_perform(curl); 742 if (res != CURLE_OK) { 743 curl_easy_cleanup(curl); 744 } 745 } 746 curl_global_cleanup(); 747 } 748 } 749 } 750 751 ``` 752 753 ### Running the java code that uses libcurl 754 755 ```sh 756 757 javac -cp curl.jar CurlMain.java 758 java -cp curl.jar:. CurlMain <url> 759 760 ``` 761 762 ## Using unistd.h from Java code (Linux) 763 764 ### jextract a jar file for unistd.h 765 766 ```sh 767 768 jextract /usr/include/unistd.h -t org.unix -o unistd.jar 769 770 ``` 771 772 ### Java code that calls getpid 773 774 ```java 775 776 import java.foreign.*; 777 import java.lang.invoke.*; 778 import org.unix.unistd; 779 780 781 public class Getpid { 782 public static void main(String[] args) { 783 // bind unistd interface 784 var u = Libraries.bind(MethodHandles.lookup(), unistd.class); 785 // call getpid from the unistd.h 786 System.out.println(u.getpid()); 787 // check process id from Java API! 788 System.out.println(ProcessHandle.current().pid()); 789 } 790 } 791 792 ``` 793 794 ### Running the Java code that uses getpid 795 796 ```sh 797 798 javac -cp unistd.jar Getpid.java 799 800 java -cp unistd.jar:. Getpid 801 802 ``` 803 804 805 ## Using OpenGL graphic library (Ubuntu 16.04) 806 807 OpenGL is a popular portable graphic library: [https://www.opengl.org/](https://www.opengl.org/) 808 809 ### Installing OpenGL (Ubuntu 16.04) 810 811 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. 812 813 OpenGL is always coupled with a bunch of other libraries, namely GLU and glut. You can install all those libraries using `apt`, as follows: 814 815 ```sh 816 817 sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev 818 819 ``` 820 821 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/`. 822 823 ### jextracting OpenGL (Ubuntu 16.04) 824 825 To extract the opengl libraries the following command suffices: 826 827 ```sh 828 829 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 830 831 ``` 832 833 Since glut depends on the other libraries (GLU and GL), it is not necessary to give additional headers to jextract. 834 835 ### Java sample code that uses the OpenGL library 836 837 ```java 838 import java.foreign.NativeTypes; 839 import java.foreign.Scope; 840 import java.foreign.memory.Array; 841 import java.foreign.memory.Pointer; 842 843 import static opengl.gl_h.*; 844 import static opengl.freeglut_std_h.*; 845 846 public class Teapot { 847 848 float rot = 0; 849 850 Teapot(Scope sc) { 851 // Misc Parameters 852 Array<Float> pos = sc.allocateArray(NativeTypes.FLOAT, new float[] {0.0f, 15.0f, -15.0f, 0}); 853 Array<Float> spec = sc.allocateArray(NativeTypes.FLOAT, new float[] {1, 1, 1, 0}); 854 Array<Float> shini = sc.allocateArray(NativeTypes.FLOAT, new float[] {113}); 855 856 // Reset Background 857 glClearColor(0, 0, 0, 0); 858 859 // Setup Lighting 860 glShadeModel(GL_SMOOTH); 861 glLightfv(GL_LIGHT0, GL_POSITION, pos.elementPointer()); 862 glLightfv(GL_LIGHT0, GL_AMBIENT, spec.elementPointer()); 863 glLightfv(GL_LIGHT0, GL_DIFFUSE, spec.elementPointer()); 864 glLightfv(GL_LIGHT0, GL_SPECULAR, spec.elementPointer()); 865 glMaterialfv(GL_FRONT, GL_SHININESS, shini.elementPointer()); 866 glEnable(GL_LIGHTING); 867 glEnable(GL_LIGHT0); 868 glEnable(GL_DEPTH_TEST); 869 } 870 871 void display() { 872 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 873 glPushMatrix(); 874 glRotatef(-20, 1, 1, 0); 875 glRotatef(rot, 0, 1, 0); 876 glutSolidTeapot(0.5); 877 glPopMatrix(); 878 glutSwapBuffers(); 879 } 880 881 void onIdle() { 882 rot += 0.1; 883 glutPostRedisplay(); 884 } 885 886 public static void main(String[] args) { 887 try (Scope sc = opengl.gl_h.scope().fork()) { 888 Pointer<Integer> argc = sc.allocate(NativeTypes.INT32); 889 argc.set(0); 890 glutInit(argc, Pointer.ofNull()); 891 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); 892 glutInitWindowSize(900, 900); 893 glutCreateWindow(sc.allocateCString("Hello Panama!")); 894 Teapot teapot = new Teapot(sc); 895 glutDisplayFunc(sc.allocateCallback(teapot::display)); 896 glutIdleFunc(sc.allocateCallback(teapot::onIdle)); 897 glutMainLoop(); 898 } 899 } 900 } 901 ``` 902 ### Running the Java code that uses OpenGL (Ubuntu 16.04) 903 904 ```sh 905 906 javac -cp opengl.jar Teapot.java 907 908 java -cp opengl.jar:. Teapot 909 910 ``` 911 912 ## Using OpenGL graphic library (Windows) 913 914 ### Installing OpenGL 915 916 Download the freeglut package for MSVC at [https://www.transmissionzero.co.uk/software/freeglut-devel/](https://www.transmissionzero.co.uk/software/freeglut-devel/) 917 918 Extract the freeglut zip. 919 920 ### jextracting OpenGL 921 922 Navigate to the root directory of the extracted zip and run the following commands: 923 924 ```powershell 925 $inc = "C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0" 926 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 927 ``` 928 929 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\`). 930 931 There are a bunch of warnings generated, but as long as the jar file is generated in the working directory the extraction was successful. 932 933 ### Java sample code that uses the OpenGL library 934 935 This is the same as in the Ubuntu section 936 937 ### Running the Java code that uses OpenGL 938 939 ```powershell 940 javac -cp .\opengl.jar Teapot.java 941 java -cp "opengl.jar;." Teapot 942 ``` 943 944 ## Using TensorFlow C API (Mac OS) 945 946 Quoted from [https://www.tensorflow.org/install/lang_c](https://www.tensorflow.org/install/lang_c) 947 948 "TensorFlow provides a C API that can be used to build bindings for other 949 languages. The API is defined in c_api.h and designed for simplicity and 950 uniformity rather than convenience." 951 952 953 ### Installing libtensorflow 954 955 You can follow the setup procedure as described in the above page. 956 957 Alternatively, on Mac, you can install libtensorflow using HomeBrew 958 959 ```sh 960 961 brew install libtensorflow 962 963 ``` 964 965 Tensorflow ship the libtensorflow with an .so extension, this doesn't work 966 well for java on MacOS as java expect .dylib extension. To work around this, 967 create a symbolic link. 968 969 ```sh 970 971 sudo ln -s /usr/local/lib/libtensorflow.so /usr/local/lib/libtensorflow.dylib 972 973 ``` 974 975 ### jextracting libtensorflow c_api.h 976 977 The following command can be used to extract c_api.h. 978 979 ```sh 980 981 jextract -C -x -C c++ \ 982 -L /usr/local/lib -l tensorflow --record-library-path \ 983 -o tf.jar -t org.tensorflow.panama \ 984 /usr/local/include/tensorflow/c/c_api.h 985 986 ``` 987 988 The caveat to extract tensorflow C API is that it declare function prototype 989 without argument in C++ style, for example, TF_Version(), which is considered 990 incomplete C function prototype instead of C style as in TF_Version(void). An 991 incomplete function prototype will become vararg funciton. To avoid that, we 992 need to pass clang '-x c++' options to jextract with '-C -x -C c++' 993 994 ### Java sample code that uses tensorflow library 995 996 ```java 997 998 import java.foreign.NativeTypes; 999 import java.foreign.Scope; 1000 import java.foreign.memory.Array; 1001 import java.foreign.memory.LayoutType; 1002 import java.foreign.memory.Pointer; 1003 import org.tensorflow.panama.c_api.TF_DataType; 1004 import org.tensorflow.panama.c_api.TF_Graph; 1005 import org.tensorflow.panama.c_api.TF_Operation; 1006 import org.tensorflow.panama.c_api.TF_OperationDescription; 1007 import org.tensorflow.panama.c_api.TF_Output; 1008 import org.tensorflow.panama.c_api.TF_Session; 1009 import org.tensorflow.panama.c_api.TF_SessionOptions; 1010 import org.tensorflow.panama.c_api.TF_Status; 1011 import org.tensorflow.panama.c_api.TF_Tensor; 1012 1013 import static org.tensorflow.panama.c_api_h.*; 1014 import static org.tensorflow.panama.c_api_h.TF_DataType.*; 1015 1016 public class TensorFlowExample { 1017 static Pointer<TF_Operation> PlaceHolder(Pointer<TF_Graph> graph, Pointer<TF_Status> status, 1018 @TF_DataType int dtype, String name) { 1019 try (var s = scope().fork()) { 1020 Pointer<TF_OperationDescription> desc = TF_NewOperation(graph, 1021 s.allocateCString("Placeholder"), s.allocateCString(name)); 1022 TF_SetAttrType(desc, s.allocateCString("dtype"), TF_FLOAT); 1023 return TF_FinishOperation(desc, status); 1024 } 1025 } 1026 1027 static Pointer<TF_Operation> ConstValue(Pointer<TF_Graph> graph, Pointer<TF_Status> status, 1028 Pointer<TF_Tensor> tensor, String name) { 1029 try (var s = scope().fork()) { 1030 Pointer<TF_OperationDescription> desc = TF_NewOperation(graph, 1031 s.allocateCString("Const"), s.allocateCString(name)); 1032 TF_SetAttrTensor(desc, s.allocateCString("value"), tensor, status); 1033 TF_SetAttrType(desc, s.allocateCString("dtype"), TF_TensorType(tensor)); 1034 return TF_FinishOperation(desc, status); 1035 } 1036 } 1037 1038 static Pointer<TF_Operation> Add(Pointer<TF_Graph> graph, Pointer<TF_Status> status, 1039 Pointer<TF_Operation> one, Pointer<TF_Operation> two, 1040 String name) { 1041 try (var s = scope().fork()) { 1042 Pointer<TF_OperationDescription> desc = TF_NewOperation(graph, 1043 s.allocateCString("AddN"), s.allocateCString(name)); 1044 Array<TF_Output> add_inputs = s.allocateArray( 1045 LayoutType.ofStruct(TF_Output.class),2); 1046 add_inputs.get(0).oper$set(one); 1047 add_inputs.get(0).index$set(0); 1048 add_inputs.get(1).oper$set(two); 1049 add_inputs.get(1).index$set(0); 1050 TF_AddInputList(desc, add_inputs.elementPointer(), 2); 1051 return TF_FinishOperation(desc, status); 1052 } 1053 } 1054 1055 public static void main(String... args) { 1056 System.out.println("TensorFlow C library version: " + Pointer.toString(TF_Version())); 1057 1058 Pointer<TF_Graph> graph = TF_NewGraph(); 1059 Pointer<TF_SessionOptions> options = TF_NewSessionOptions(); 1060 Pointer<TF_Status> status = TF_NewStatus(); 1061 Pointer<TF_Session> session = TF_NewSession(graph, options, status); 1062 1063 float in_val_one = 4.0f; 1064 float const_two = 2.0f; 1065 1066 Pointer<TF_Tensor> tensor_in = TF_AllocateTensor(TF_FLOAT, Pointer.ofNull(), 0, Float.BYTES); 1067 TF_TensorData(tensor_in).cast(NativeTypes.FLOAT).set(in_val_one); 1068 Pointer<TF_Tensor> tensor_const_two = TF_AllocateTensor(TF_FLOAT, Pointer.ofNull(), 0, Float.BYTES); 1069 TF_TensorData(tensor_const_two).cast(NativeTypes.FLOAT).set(const_two); 1070 1071 // Operations 1072 Pointer<TF_Operation> feed = PlaceHolder(graph, status, TF_FLOAT, "feed"); 1073 Pointer<TF_Operation> two = ConstValue(graph, status, tensor_const_two, "const"); 1074 Pointer<TF_Operation> add = Add(graph, status, feed, two, "add"); 1075 1076 1077 try (var s = scope().fork()) { 1078 var ltPtrTensor = LayoutType.ofStruct(TF_Tensor.class).pointer(); 1079 1080 // Session Inputs 1081 TF_Output input_operations = s.allocateStruct(TF_Output.class); 1082 input_operations.oper$set(feed); 1083 input_operations.index$set(0); 1084 Pointer<Pointer<TF_Tensor>> input_tensors = s.allocate(ltPtrTensor); 1085 input_tensors.set(tensor_in); 1086 1087 // Session Outputs 1088 TF_Output output_operations = s.allocateStruct(TF_Output.class); 1089 output_operations.oper$set(add); 1090 output_operations.index$set(0); 1091 Pointer<Pointer<TF_Tensor>> output_tensors = s.allocate(ltPtrTensor); 1092 TF_SessionRun(session, Pointer.ofNull(), 1093 // Inputs 1094 input_operations.ptr(), input_tensors, 1, 1095 // Outputs 1096 output_operations.ptr(), output_tensors, 1, 1097 // Target operations 1098 Pointer.ofNull(), 0, Pointer.ofNull(), 1099 status); 1100 1101 System.out.println(String.format("Session Run Status: %d - %s", 1102 TF_GetCode(status), Pointer.toString(TF_Message(status)))); 1103 Pointer<TF_Tensor> tensor_out = output_tensors.get(); 1104 System.out.println("Output Tensor Type: " + TF_TensorType(tensor_out)); 1105 float outval = TF_TensorData(tensor_out).cast(NativeTypes.FLOAT).get(); 1106 System.out.println("Output Tensor Value: " + outval); 1107 1108 TF_CloseSession(session, status); 1109 TF_DeleteSession(session, status); 1110 1111 TF_DeleteSessionOptions(options); 1112 1113 TF_DeleteGraph(graph); 1114 1115 TF_DeleteTensor(tensor_in); 1116 TF_DeleteTensor(tensor_out); 1117 TF_DeleteTensor(tensor_const_two); 1118 1119 TF_DeleteStatus(status); 1120 } 1121 } 1122 } 1123 1124 ``` 1125 1126 ### Compiling and running the above TensorFlow sample 1127 1128 ```sh 1129 1130 javac -cp tf.jar TensorFlowExample.java 1131 1132 java -cp tf.jar:. TensorFlowExample 1133 1134 ``` 1135 1136 ## Using TensorFlow C API (Windows) 1137 1138 ### Installing libtensorflow 1139 1140 You can download a binary distribution from [https://www.tensorflow.org/install/lang_c](https://www.tensorflow.org/install/lang_c) 1141 1142 Extract the zip file. 1143 1144 ### jextracting libtensorflow c_api.h 1145 1146 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: 1147 1148 ```C 1149 TF_Version() -> TF_Version(void) 1150 TF_NewGraph() -> TF_NewGraph(void) 1151 TF_NewSessionOptions() -> TF_NewSessionOptions(void) 1152 TF_NewStatus() -> TF_NewStatus(void) 1153 TF_NewBuffer() -> TF_NewBuffer(void) 1154 TF_NewImportGraphDefOptions() -> TF_NewImportGraphDefOptions(void) 1155 TF_GetAllOpList() -> TF_GetAllOpList(void) 1156 ``` 1157 Once you've done this you can use the following jextract command from the libtensorflow root directory: 1158 1159 ```powershell 1160 jextract -L .\lib -l tensorflow -o tf.jar -t "org.tensorflow.panama" --record-library-path .\include\tensorflow\c\c_api.h 1161 ``` 1162 1163 ### Java sample code that uses tensorflow library 1164 1165 This is the same as for the Mac OS section. 1166 1167 ### Compiling and running the above TensorFlow sample 1168 1169 ```powershell 1170 javac -cp tf.jar TensorFlowExample.java 1171 java -cp "tf.jar;." TensorFlowExample 1172 ```