8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package com.sun.tools.jextract; 24 25 import jdk.internal.clang.*; 26 import jdk.internal.foreign.LibrariesHelper; 27 28 import java.io.File; 29 import java.io.IOException; 30 import java.io.OutputStream; 31 import java.io.PrintWriter; 32 import java.io.UncheckedIOException; 33 import java.lang.invoke.MethodHandles; 34 import java.foreign.Library; 35 import java.nio.file.Files; 36 import java.nio.file.Path; 37 import java.util.ArrayList; 38 import java.util.Arrays; 39 import java.util.Collections; 40 import java.util.HashMap; 41 import java.util.List; 42 import java.util.Map; 43 import java.util.Set; 44 import java.util.TreeSet; 45 import java.util.function.Function; 46 import java.util.function.Predicate; 47 import java.util.jar.JarOutputStream; 48 import java.util.logging.Logger; 49 import java.util.regex.Pattern; 50 import java.util.stream.Collectors; 51 import java.util.zip.ZipEntry; 52 53 import static java.nio.file.StandardOpenOption.CREATE; 54 import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; 55 import static java.nio.file.StandardOpenOption.WRITE; 56 57 /** 58 * The setup for the tool execution 59 */ 60 public final class Context { 61 // package name to TypeDictionary 62 private final Map<String, TypeDictionary> tdMap; 419 logger.config(() -> "File " + header + " code generation is not activated!"); 420 return; 421 } 422 List<AsmCodeFactory> l = mapPkgCf.computeIfAbsent(pkg, k -> new ArrayList<>()); 423 l.add(cf); 424 logger.config(() -> "Add cf " + cf + " to pkg " + pkg + ", size is now " + l.size()); 425 }); 426 return Collections.unmodifiableMap(mapPkgCf); 427 } 428 429 public Map<String, byte[]> collectClasses(String... pkgs) { 430 final Map<String, byte[]> rv = new HashMap<>(); 431 final Map<String, List<AsmCodeFactory>> mapPkgCf = getPkgCfMap(); 432 for (String pkg_name : pkgs) { 433 mapPkgCf.getOrDefault(pkg_name, Collections.emptyList()) 434 .forEach(cf -> rv.putAll(cf.collect())); 435 } 436 return Collections.unmodifiableMap(rv); 437 } 438 439 void collectClassFiles(Path destDir, String... pkgs) throws IOException { 440 try { 441 collectClasses(pkgs).entrySet().stream().forEach(e -> { 442 try { 443 String path = e.getKey().replace('.', File.separatorChar) + ".class"; 444 logger.fine(() -> "Writing " + path); 445 Path fullPath = destDir.resolve(path).normalize(); 446 Files.createDirectories(fullPath.getParent()); 447 try (OutputStream fos = Files.newOutputStream(fullPath)) { 448 fos.write(e.getValue()); 449 fos.flush(); 450 } 451 } catch (IOException ioe) { 452 throw new UncheckedIOException(ioe); 453 } 454 }); 455 } catch (UncheckedIOException uioe) { 456 throw uioe.getCause(); 457 } 458 } 459 460 private void writeJar(AsmCodeFactory cf, JarOutputStream jar) { 461 cf.collect().entrySet().stream().forEach(e -> { 462 try { 463 String path = e.getKey().replace('.', File.separatorChar) + ".class"; 464 logger.fine(() -> "Add " + path); 465 jar.putNextEntry(new ZipEntry(path)); 466 jar.write(e.getValue()); 467 jar.closeEntry(); 468 } catch (IOException ioe) { 469 throw new UncheckedIOException(ioe); 470 } 471 }); 472 } 473 474 public void collectJarFile(final JarOutputStream jos, String... pkgs) { 475 final Map<String, List<AsmCodeFactory>> mapPkgCf = getPkgCfMap(); 476 477 for (String pkg_name : pkgs) { 478 // convert '.' to '/' to use as a path 479 String entryName = Utils.toInternalName(pkg_name, ""); 480 // package folder 481 if (!entryName.isEmpty()) { 482 try { 483 jos.putNextEntry(new ZipEntry(entryName)); 484 } catch (IOException ex) { 485 throw new UncheckedIOException(ex); 486 } 487 } 488 logger.fine(() -> "Produce for package " + pkg_name); 489 mapPkgCf.getOrDefault(pkg_name, Collections.emptyList()) 490 .forEach(cf -> writeJar(cf, jos)); 491 } 492 } 493 494 void collectJarFile(final Path jar, String... pkgs) throws IOException { 495 logger.info(() -> "Collecting jar file " + jar); 496 try (OutputStream os = Files.newOutputStream(jar, CREATE, TRUNCATE_EXISTING, WRITE); 497 JarOutputStream jo = new JarOutputStream(os)) { 498 collectJarFile(jo, pkgs); 499 } catch (UncheckedIOException uioe) { 500 throw uioe.getCause(); 501 } 502 } 503 504 /** 505 * Perform a local lookup, any undefined type will cause a JType 506 * be defined within origin scope. 507 * 508 * @param type The libclang type 509 * @param origin The path of the file where type is encountered 510 * @return The JType 511 */ 512 JType getJType(final Type type, Path origin) { 513 Path p = origin.normalize().toAbsolutePath(); 514 515 HeaderFile hf = headerMap.get(p); 516 // We should not encounter a type if the header file reference to it is not yet processed 517 assert(null != hf); 518 if (hf == null) { | 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package com.sun.tools.jextract; 24 25 import jdk.internal.clang.*; 26 import jdk.internal.foreign.LibrariesHelper; 27 28 import java.io.ByteArrayOutputStream; 29 import java.io.File; 30 import java.io.IOException; 31 import java.io.OutputStream; 32 import java.io.PrintWriter; 33 import java.io.UncheckedIOException; 34 import java.lang.invoke.MethodHandles; 35 import java.foreign.Library; 36 import java.nio.file.Files; 37 import java.nio.file.Path; 38 import java.util.ArrayList; 39 import java.util.Arrays; 40 import java.util.Collections; 41 import java.util.HashMap; 42 import java.util.List; 43 import java.util.Map; 44 import java.util.Properties; 45 import java.util.Set; 46 import java.util.TreeSet; 47 import java.util.function.Function; 48 import java.util.function.Predicate; 49 import java.util.jar.JarOutputStream; 50 import java.util.logging.Logger; 51 import java.util.regex.Pattern; 52 import java.util.stream.Collectors; 53 import java.util.zip.ZipEntry; 54 55 import static java.nio.file.StandardOpenOption.CREATE; 56 import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; 57 import static java.nio.file.StandardOpenOption.WRITE; 58 59 /** 60 * The setup for the tool execution 61 */ 62 public final class Context { 63 // package name to TypeDictionary 64 private final Map<String, TypeDictionary> tdMap; 421 logger.config(() -> "File " + header + " code generation is not activated!"); 422 return; 423 } 424 List<AsmCodeFactory> l = mapPkgCf.computeIfAbsent(pkg, k -> new ArrayList<>()); 425 l.add(cf); 426 logger.config(() -> "Add cf " + cf + " to pkg " + pkg + ", size is now " + l.size()); 427 }); 428 return Collections.unmodifiableMap(mapPkgCf); 429 } 430 431 public Map<String, byte[]> collectClasses(String... pkgs) { 432 final Map<String, byte[]> rv = new HashMap<>(); 433 final Map<String, List<AsmCodeFactory>> mapPkgCf = getPkgCfMap(); 434 for (String pkg_name : pkgs) { 435 mapPkgCf.getOrDefault(pkg_name, Collections.emptyList()) 436 .forEach(cf -> rv.putAll(cf.collect())); 437 } 438 return Collections.unmodifiableMap(rv); 439 } 440 441 private static final String JEXTRACT_MANIFEST = "META-INFO" + File.separatorChar + "jextract.properties"; 442 443 @SuppressWarnings("deprecation") 444 private byte[] getJextractProperties(String[] args) { 445 Properties props = new Properties(); 446 props.setProperty("os.name", System.getProperty("os.name")); 447 props.setProperty("os.version", System.getProperty("os.version")); 448 props.setProperty("os.arch", System.getProperty("os.arch")); 449 props.setProperty("jextract.args", Arrays.toString(args)); 450 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 451 props.save(baos, "jextract meta data"); 452 return baos.toByteArray(); 453 } 454 455 void collectClassFiles(Path destDir, String[] args, String... pkgs) throws IOException { 456 try { 457 collectClasses(pkgs).entrySet().stream().forEach(e -> { 458 try { 459 String path = e.getKey().replace('.', File.separatorChar) + ".class"; 460 logger.fine(() -> "Writing " + path); 461 Path fullPath = destDir.resolve(path).normalize(); 462 Files.createDirectories(fullPath.getParent()); 463 try (OutputStream fos = Files.newOutputStream(fullPath)) { 464 fos.write(e.getValue()); 465 fos.flush(); 466 } 467 } catch (IOException ioe) { 468 throw new UncheckedIOException(ioe); 469 } 470 }); 471 472 Path propsPath = destDir.resolve(JEXTRACT_MANIFEST).normalize(); 473 Files.createDirectories(propsPath.getParent()); 474 try (OutputStream fos = Files.newOutputStream(propsPath)) { 475 fos.write(getJextractProperties(args)); 476 fos.flush(); 477 } 478 } catch (UncheckedIOException uioe) { 479 throw uioe.getCause(); 480 } 481 } 482 483 private void writeJar(AsmCodeFactory cf, JarOutputStream jar, String[] args) { 484 cf.collect().entrySet().stream().forEach(e -> { 485 try { 486 String path = e.getKey().replace('.', File.separatorChar) + ".class"; 487 logger.fine(() -> "Add " + path); 488 jar.putNextEntry(new ZipEntry(path)); 489 jar.write(e.getValue()); 490 jar.closeEntry(); 491 } catch (IOException ioe) { 492 throw new UncheckedIOException(ioe); 493 } 494 }); 495 } 496 497 public void collectJarFile(final JarOutputStream jos, String[] args, String... pkgs) { 498 final Map<String, List<AsmCodeFactory>> mapPkgCf = getPkgCfMap(); 499 500 for (String pkg_name : pkgs) { 501 // convert '.' to '/' to use as a path 502 String entryName = Utils.toInternalName(pkg_name, ""); 503 // package folder 504 if (!entryName.isEmpty()) { 505 try { 506 jos.putNextEntry(new ZipEntry(entryName)); 507 } catch (IOException ex) { 508 throw new UncheckedIOException(ex); 509 } 510 } 511 logger.fine(() -> "Produce for package " + pkg_name); 512 mapPkgCf.getOrDefault(pkg_name, Collections.emptyList()) 513 .forEach(cf -> writeJar(cf, jos, args)); 514 } 515 516 try { 517 jos.putNextEntry(new ZipEntry(JEXTRACT_MANIFEST)); 518 jos.write(getJextractProperties(args)); 519 jos.closeEntry(); 520 } catch (IOException ioe) { 521 throw new UncheckedIOException(ioe); 522 } 523 } 524 525 void collectJarFile(final Path jar, String[] args, String... pkgs) throws IOException { 526 logger.info(() -> "Collecting jar file " + jar); 527 try (OutputStream os = Files.newOutputStream(jar, CREATE, TRUNCATE_EXISTING, WRITE); 528 JarOutputStream jo = new JarOutputStream(os)) { 529 collectJarFile(jo, args, pkgs); 530 } catch (UncheckedIOException uioe) { 531 throw uioe.getCause(); 532 } 533 } 534 535 /** 536 * Perform a local lookup, any undefined type will cause a JType 537 * be defined within origin scope. 538 * 539 * @param type The libclang type 540 * @param origin The path of the file where type is encountered 541 * @return The JType 542 */ 543 JType getJType(final Type type, Path origin) { 544 Path p = origin.normalize().toAbsolutePath(); 545 546 HeaderFile hf = headerMap.get(p); 547 // We should not encounter a type if the header file reference to it is not yet processed 548 assert(null != hf); 549 if (hf == null) { |