Пример #1
0
 /**
  * Tries to find automatically include paths for {@code jni.h} and {@code jni_md.h}, as well as
  * the link and library paths for the {@code jvm} library.
  *
  * @param properties the Properties containing the paths to update
  * @param header to request support for exporting callbacks via generated header file
  */
 static void includeJavaPaths(ClassProperties properties, boolean header) {
   if (properties.getProperty("platform", "").startsWith("android")) {
     // Android includes its own jni.h file and doesn't have a jvm library
     return;
   }
   String platform = Loader.getPlatform();
   final String jvmlink =
       properties.getProperty("platform.link.prefix", "")
           + "jvm"
           + properties.getProperty("platform.link.suffix", "");
   final String jvmlib =
       properties.getProperty("platform.library.prefix", "")
           + "jvm"
           + properties.getProperty("platform.library.suffix", "");
   final String[] jnipath = new String[2];
   final String[] jvmpath = new String[2];
   FilenameFilter filter =
       new FilenameFilter() {
         @Override
         public boolean accept(File dir, String name) {
           if (new File(dir, "jni.h").exists()) {
             jnipath[0] = dir.getAbsolutePath();
           }
           if (new File(dir, "jni_md.h").exists()) {
             jnipath[1] = dir.getAbsolutePath();
           }
           if (new File(dir, jvmlink).exists()) {
             jvmpath[0] = dir.getAbsolutePath();
           }
           if (new File(dir, jvmlib).exists()) {
             jvmpath[1] = dir.getAbsolutePath();
           }
           return new File(dir, name).isDirectory();
         }
       };
   File javaHome = new File(System.getProperty("java.home")).getParentFile();
   try {
     javaHome = javaHome.getCanonicalFile();
   } catch (IOException e) {
   }
   ArrayList<File> dirs = new ArrayList<File>(Arrays.asList(javaHome.listFiles(filter)));
   while (!dirs.isEmpty()) {
     File d = dirs.remove(dirs.size() - 1);
     String dpath = d.getPath();
     for (File f : d.listFiles(filter)) {
       try {
         f = f.getCanonicalFile();
       } catch (IOException e) {
       }
       if (!dpath.startsWith(f.getPath())) {
         dirs.add(f);
       }
     }
   }
   if (jnipath[0] != null && jnipath[0].equals(jnipath[1])) {
     jnipath[1] = null;
   } else if (jnipath[0] == null) {
     String macpath = "/System/Library/Frameworks/JavaVM.framework/Headers/";
     if (new File(macpath).isDirectory()) {
       jnipath[0] = macpath;
     }
   }
   if (jvmpath[0] != null && jvmpath[0].equals(jvmpath[1])) {
     jvmpath[1] = null;
   }
   properties.addAll("platform.includepath", jnipath);
   if (platform.equals(properties.getProperty("platform", platform))) {
     if (header) {
       // We only need libjvm for callbacks exported with the header file
       properties.get("platform.link").add(0, "jvm");
       properties.addAll("platform.linkpath", jvmpath);
     }
     if (platform.startsWith("macosx")) {
       properties.addAll("platform.framework", "JavaVM");
     }
   }
 }
Пример #2
0
 /**
  * Generates a C++ source file for classes, and compiles everything in one shared library when
  * {@code compile == true}.
  *
  * @param classes the Class objects as input to Generator
  * @param outputName the output name of the shared library
  * @return the actual File generated, either the compiled library or its source
  * @throws IOException
  * @throws InterruptedException
  */
 File generateAndCompile(Class[] classes, String outputName)
     throws IOException, InterruptedException {
   File outputFile = null, outputPath = outputDirectory;
   ClassProperties p = Loader.loadProperties(classes, properties, true);
   String platform = p.getProperty("platform");
   String sourcePrefix = new File(outputPath, outputName).getPath();
   String sourceSuffix = p.getProperty("platform.source.suffix", ".cpp");
   String libraryPath = p.getProperty("platform.library.path", "");
   String libraryName =
       p.getProperty("platform.library.prefix", "")
           + outputName
           + p.getProperty("platform.library.suffix", "");
   if (outputPath == null) {
     try {
       String resourceName =
           '/' + classes[classes.length - 1].getName().replace('.', '/') + ".class";
       String resourceURL = classes[classes.length - 1].getResource(resourceName).toString();
       File packageDir =
           new File(new URI(resourceURL.substring(0, resourceURL.lastIndexOf('/') + 1)));
       File targetDir =
           libraryPath.length() > 0
               ? new File(
                   new URI(
                       resourceURL.substring(0, resourceURL.length() - resourceName.length() + 1)))
               : new File(packageDir, platform);
       outputPath = new File(targetDir, libraryPath);
       sourcePrefix = new File(packageDir, outputName).getPath();
     } catch (URISyntaxException e) {
       throw new RuntimeException(e);
     }
   }
   if (!outputPath.exists()) {
     outputPath.mkdirs();
   }
   Generator generator = new Generator(logger, p);
   String sourceFilename = sourcePrefix + sourceSuffix;
   String headerFilename = header ? sourcePrefix + ".h" : null;
   String classPath = System.getProperty("java.class.path");
   for (String s : classScanner.getClassLoader().getPaths()) {
     classPath += File.pathSeparator + s;
   }
   logger.info("Generating " + sourceFilename);
   if (generator.generate(sourceFilename, headerFilename, classPath, classes)) {
     generator.close();
     if (compile) {
       String libraryFilename = outputPath.getPath() + File.separator + libraryName;
       logger.info("Compiling " + libraryFilename);
       int exitValue = compile(sourceFilename, libraryFilename, p);
       if (exitValue == 0) {
         new File(sourceFilename).delete();
         outputFile = new File(libraryFilename);
       } else {
         System.exit(exitValue);
       }
     } else {
       outputFile = new File(sourceFilename);
     }
   } else {
     logger.info("Nothing generated for " + sourceFilename);
   }
   return outputFile;
 }
Пример #3
0
  /**
   * Starts the build process and returns an array of {@link File} produced.
   *
   * @return the array of File produced
   * @throws IOException
   * @throws InterruptedException
   * @throws ParserException
   */
  public File[] build() throws IOException, InterruptedException, ParserException {
    if (classScanner.getClasses().isEmpty()) {
      return null;
    }

    List<File> outputFiles = new ArrayList<File>();
    Map<String, List<Class>> map = new LinkedHashMap<String, List<Class>>();
    for (Class c : classScanner.getClasses()) {
      if (Loader.getEnclosingClass(c) != c) {
        continue;
      }
      ClassProperties p = Loader.loadProperties(c, properties, false);
      String target = p.getProperty("target");
      if (target != null && !c.getName().equals(target)) {
        File f = parse(classScanner.getClassLoader().getPaths(), c);
        if (f != null) {
          outputFiles.add(f);
        }
        continue;
      }
      String libraryName = outputName != null ? outputName : p.getProperty("platform.library", "");
      if (libraryName.length() == 0) {
        continue;
      }
      List<Class> classList = map.get(libraryName);
      if (classList == null) {
        map.put(libraryName, classList = new ArrayList<Class>());
      }
      classList.addAll(p.getEffectiveClasses());
    }
    for (String libraryName : map.keySet()) {
      List<Class> classList = map.get(libraryName);
      Class[] classArray = classList.toArray(new Class[classList.size()]);
      File f = generateAndCompile(classArray, libraryName);
      if (f != null) {
        outputFiles.add(f);
        if (copyLibs) {
          // Do not copy library files from inherit properties ...
          ClassProperties p = Loader.loadProperties(classArray, properties, false);
          List<String> preloads = new ArrayList<String>();
          preloads.addAll(p.get("platform.preload"));
          preloads.addAll(p.get("platform.link"));
          // ... but we should use all the inherited paths!
          p = Loader.loadProperties(classArray, properties, true);

          File directory = f.getParentFile();
          for (String s : preloads) {
            URL[] urls = Loader.findLibrary(null, p, s);
            File fi;
            try {
              fi = new File(urls[0].toURI());
            } catch (Exception e) {
              continue;
            }
            File fo = new File(directory, fi.getName());
            if (fi.exists() && !outputFiles.contains(fo)) {
              logger.info("Copying " + fi);
              FileInputStream fis = new FileInputStream(fi);
              FileOutputStream fos = new FileOutputStream(fo);
              byte[] buffer = new byte[1024];
              int length;
              while ((length = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, length);
              }
              fos.close();
              fis.close();
              outputFiles.add(fo);
            }
          }
        }
      }
    }

    File[] files = outputFiles.toArray(new File[outputFiles.size()]);
    if (jarPrefix != null && files.length > 0) {
      File jarFile = new File(jarPrefix + "-" + properties.get("platform") + ".jar");
      File d = jarFile.getParentFile();
      if (d != null && !d.exists()) {
        d.mkdir();
      }
      createJar(
          jarFile,
          outputDirectory == null ? classScanner.getClassLoader().getPaths() : null,
          files);
    }
    return files;
  }
Пример #4
0
  /**
   * Launches and waits for the native compiler to produce a native shared library.
   *
   * @param sourceFilename the C++ source filename
   * @param outputFilename the output filename of the shared library
   * @param properties the Properties detailing the compiler options to use
   * @return the result of {@link Process#waitFor()}
   * @throws IOException
   * @throws InterruptedException
   */
  int compile(String sourceFilename, String outputFilename, ClassProperties properties)
      throws IOException, InterruptedException {
    ArrayList<String> command = new ArrayList<String>();

    includeJavaPaths(properties, header);

    String platform = Loader.getPlatform();
    String compilerPath = properties.getProperty("platform.compiler");
    command.add(compilerPath);

    {
      String p = properties.getProperty("platform.sysroot.prefix", "");
      for (String s : properties.get("platform.sysroot")) {
        if (new File(s).isDirectory()) {
          if (p.endsWith(" ")) {
            command.add(p.trim());
            command.add(s);
          } else {
            command.add(p + s);
          }
        }
      }
    }

    {
      String p = properties.getProperty("platform.includepath.prefix", "");
      for (String s : properties.get("platform.includepath")) {
        if (new File(s).isDirectory()) {
          if (p.endsWith(" ")) {
            command.add(p.trim());
            command.add(s);
          } else {
            command.add(p + s);
          }
        }
      }
    }

    command.add(sourceFilename);

    Collection<String> allOptions = properties.get("platform.compiler.*");
    if (allOptions.isEmpty()) {
      allOptions.add("default");
    }
    for (String s : allOptions) {
      if (s == null || s.length() == 0) {
        continue;
      }
      String p = "platform.compiler." + s;
      String options = properties.getProperty(p);
      if (options != null && options.length() > 0) {
        command.addAll(Arrays.asList(options.split(" ")));
      } else if (!"default".equals(s)) {
        logger.warn("Could not get the property named \"" + p + "\"");
      }
    }

    command.addAll(compilerOptions);

    String output = properties.getProperty("platform.compiler.output");
    if (output != null && output.length() > 0) {
      command.addAll(Arrays.asList(output.split(" ")));
    }

    if (output == null || output.length() == 0 || output.endsWith(" ")) {
      command.add(outputFilename);
    } else {
      command.add(command.remove(command.size() - 1) + outputFilename);
    }

    {
      String p = properties.getProperty("platform.linkpath.prefix", "");
      String p2 = properties.getProperty("platform.linkpath.prefix2");
      for (String s : properties.get("platform.linkpath")) {
        if (new File(s).isDirectory()) {
          if (p.endsWith(" ")) {
            command.add(p.trim());
            command.add(s);
          } else {
            command.add(p + s);
          }
          if (p2 != null) {
            if (p2.endsWith(" ")) {
              command.add(p2.trim());
              command.add(s);
            } else {
              command.add(p2 + s);
            }
          }
        }
      }
    }

    {
      String p = properties.getProperty("platform.link.prefix", "");
      String x = properties.getProperty("platform.link.suffix", "");
      int i = command.size(); // to inverse order and satisfy typical compilers
      for (String s : properties.get("platform.link")) {
        String[] libnameversion = s.split("@");
        if (libnameversion.length == 3 && libnameversion[1].length() == 0) {
          // Only use the version number when the user gave us a double @
          s = libnameversion[0] + libnameversion[2];
        } else {
          s = libnameversion[0];
        }
        if (p.endsWith(" ") && x.startsWith(" ")) {
          command.add(i, p.trim());
          command.add(i + 1, s);
          command.add(i + 2, x.trim());
        } else if (p.endsWith(" ")) {
          command.add(i, p.trim());
          command.add(i + 1, s + x);
        } else if (x.startsWith(" ")) {
          command.add(i, p + s);
          command.add(i + 1, x.trim());
        } else {
          command.add(i, p + s + x);
        }
      }
    }

    {
      String p = properties.getProperty("platform.frameworkpath.prefix", "");
      for (String s : properties.get("platform.frameworkpath")) {
        if (new File(s).isDirectory()) {
          if (p.endsWith(" ")) {
            command.add(p.trim());
            command.add(s);
          } else {
            command.add(p + s);
          }
        }
      }
    }

    {
      String p = properties.getProperty("platform.framework.prefix", "");
      String x = properties.getProperty("platform.framework.suffix", "");
      for (String s : properties.get("platform.framework")) {
        if (p.endsWith(" ") && x.startsWith(" ")) {
          command.add(p.trim());
          command.add(s);
          command.add(x.trim());
        } else if (p.endsWith(" ")) {
          command.add(p.trim());
          command.add(s + x);
        } else if (x.startsWith(" ")) {
          command.add(p + s);
          command.add(x.trim());
        } else {
          command.add(p + s + x);
        }
      }
    }

    String text = "";
    boolean windows = platform.startsWith("windows");
    for (String s : command) {
      boolean hasSpaces = s.indexOf(" ") > 0;
      if (hasSpaces) {
        text += windows ? "\"" : "'";
      }
      text += s;
      if (hasSpaces) {
        text += windows ? "\"" : "'";
      }
      text += " ";
    }
    logger.info(text);

    ProcessBuilder pb = new ProcessBuilder(command);
    if (environmentVariables != null) {
      pb.environment().putAll(environmentVariables);
    }
    return pb.inheritIO().start().waitFor();
  }