All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bytedeco.javacpp.tools.Builder Maven / Gradle / Ivy

There is a newer version: 1.5.11
Show newest version
/*
 * Copyright (C) 2011-2016 Samuel Audet
 *
 * Licensed either under the Apache License, Version 2.0, or (at your option)
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation (subject to the "Classpath" exception),
 * either version 2, or any later version (collectively, the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *     http://www.gnu.org/licenses/
 *     http://www.gnu.org/software/classpath/license.html
 *
 * or as provided in the LICENSE.txt file that accompanied this code.
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.bytedeco.javacpp.tools;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;

import org.bytedeco.javacpp.ClassProperties;
import org.bytedeco.javacpp.Loader;

/**
 * The Builder is responsible for coordinating efforts between the Parser, the
 * Generator, and the native compiler. It contains the main() method, and basically
 * takes care of the tasks one would expect from a command line build tool, but
 * can also be used programmatically by setting its properties and calling build().
 *
 * @author Samuel Audet
 */
public class Builder {

    /**
     * Calls {@link Parser#parse(File, String[], Class)} after creating an instance of the Class.
     *
     * @param classPath an array of paths to try to load header files from
     * @param cls The class annotated with {@link org.bytedeco.javacpp.annotation.Properties}
     *            and implementing {@link InfoMapper}
     * @return the target File produced
     * @throws IOException on Java target file writing error
     * @throws ParserException on C/C++ header file parsing error
     */
    File parse(String[] classPath, Class cls) throws IOException, ParserException {
        return new Parser(logger, properties).parse(outputDirectory, classPath, cls);
    }

    /**
     * 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
     */
    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;
        try {
            javaHome = new File(System.getProperty("java.home")).getParentFile().getCanonicalFile();
        } catch (IOException | NullPointerException e) {
            logger.warn("Could not include header files from java.home:" + e);
            return;
        }
        ArrayList dirs = new ArrayList(Arrays.asList(javaHome.listFiles(filter)));
        while (!dirs.isEmpty()) {
            File d = dirs.remove(dirs.size() - 1);
            String dpath = d.getPath();
            File[] files = d.listFiles(filter);
            if (dpath == null || files == null) {
                continue;
            }
            for (File f : files) {
                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");
            }
        }
    }

    /**
     * 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, File workingDirectory)
            throws IOException, InterruptedException {
        ArrayList command = new ArrayList();

        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);

        List allOptions = properties.get("platform.compiler.*");
        if (!allOptions.contains("!default") && !allOptions.contains("default")) {
            allOptions.add(0, "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) && !"default".equals(s)) {
                logger.warn("Could not get the property named \"" + p + "\"");
            }
        }

        command.addAll(compilerOptions);

        String output = properties.getProperty("platform.compiler.output");
        for (int i = 1; i < 2 || output != null; i++,
                output = properties.getProperty("platform.compiler.output" + i)) {
            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("#")[0].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);
        // Use the library output path as the working directory so that all
        // build files, including intermediate ones from MSVC, are dumped there
        pb.directory(workingDirectory);
        if (environmentVariables != null) {
            pb.environment().putAll(environmentVariables);
        }
        return pb.inheritIO().start().waitFor();
    }

    /**
     * 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) {
            URI uri = null;
            try {
                String resourceName = '/' + classes[classes.length - 1].getName().replace('.', '/')  + ".class";
                String resourceURL = classes[classes.length - 1].getResource(resourceName).toString();
                uri = new URI(resourceURL.substring(0, resourceURL.lastIndexOf('/') + 1));
                boolean isFile = "file".equals(uri.getScheme());
                String classPath = classScanner.getClassLoader().getPaths()[0];
                // If our class is not a file, use first path of the user class loader as base for our output path
                File packageDir = isFile ? new File(uri)
                                         : new File(classPath, resourceName.substring(0, resourceName.lastIndexOf('/') + 1));
                // Output to the library path inside of the class path, if provided by the user
                uri = new URI(resourceURL.substring(0, resourceURL.length() - resourceName.length() + 1));
                File targetDir = libraryPath.length() > 0
                        ? (isFile ? new File(uri) : new File(classPath))
                        : new File(packageDir, platform);
                outputPath = new File(targetDir, libraryPath);
                sourcePrefix = new File(packageDir, outputName).getPath();
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            } catch (IllegalArgumentException e) {
                throw new RuntimeException("URI: " + uri, 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) {
                logger.info("Compiling " + outputPath.getPath() + File.separator + libraryName);
                int exitValue = compile(sourceFilename, libraryName, p, outputPath);
                if (exitValue == 0) {
                    if (deleteJniFiles) {
                        logger.info("Deleting " + sourceFilename);
                        new File(sourceFilename).delete();
                    } else {
                        logger.info("Keeping " + sourceFilename);
                    }
                    outputFile = new File(outputPath, libraryName);
                } else {
                    System.exit(exitValue);
                }
            } else {
                outputFile = new File(sourceFilename);
            }
        } else {
            logger.info("Nothing generated for " + sourceFilename);
        }
        return outputFile;
    }

    /**
     * Stores all the files in the given JAR file. Also attempts to root the paths
     * of the filenames to each element of a list of classpaths.
     *
     * @param jarFile the JAR file to create
     * @param classPath an array of paths to try to use as root for classes
     * @param files a list of files to store in the JAR file
     * @throws IOException
     */
    void createJar(File jarFile, String[] classPath, File ... files) throws IOException {
        logger.info("Creating " + jarFile);
        JarOutputStream jos = new JarOutputStream(new FileOutputStream(jarFile));
        for (File f : files) {
            String name = f.getPath();
            if (classPath != null) {
                // Store only the path relative to the classpath so that
                // our Loader may use the package name of the associated
                // class to get the file as a resource from the ClassLoader.
                String[] names = new String[classPath.length];
                for (int i = 0; i < classPath.length; i++) {
                    String path = new File(classPath[i]).getCanonicalPath();
                    if (name.startsWith(path)) {
                        names[i] = name.substring(path.length() + 1);
                    }
                }
                // Retain only the shortest relative name.
                for (int i = 0; i < names.length; i++) {
                    if (names[i] != null && names[i].length() < name.length()) {
                        name = names[i];
                    }
                }
            }
            ZipEntry e = new ZipEntry(name.replace(File.separatorChar, '/'));
            e.setTime(f.lastModified());
            jos.putNextEntry(e);
            FileInputStream fis = new FileInputStream(f);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) != -1) {
                jos.write(buffer, 0, length);
            }
            fis.close();
            jos.closeEntry();
        }
        jos.close();
    }

    /**
     * Default constructor that simply initializes everything.
     */
    public Builder() {
        this(Logger.create(Builder.class));
    }
    /**
     * Constructor that simply initializes everything.
     * @param logger where to send messages
     */
    public Builder(Logger logger) {
        this.logger = logger;
        System.setProperty("org.bytedeco.javacpp.loadlibraries", "false");
        properties = Loader.loadProperties();
        classScanner = new ClassScanner(logger, new ArrayList(),
                new UserClassLoader(Thread.currentThread().getContextClassLoader()));
        compilerOptions = new ArrayList();
    }

    /** Logger where to send debug, info, warning, and error messages. */
    final Logger logger;
    /** The directory where the generated files and compiled shared libraries get written to.
     *  By default they are placed in the same directory as the {@code .class} file. */
    File outputDirectory = null;
    /** The name of the output generated source file or shared library. This enables single-
     *  file output mode. By default, the top-level enclosing classes get one file each. */
    String outputName = null;
    /** The name of the JAR file to create, if not {@code null}. */
    String jarPrefix = null;
    /** If true, compiles the generated source file to a shared library and deletes source. */
    boolean compile = true;
    /** If true, preserves the generated C++ JNI files after compilation */
    boolean deleteJniFiles = true;
    /** If true, also generates C++ header files containing declarations of callback functions. */
    boolean header = false;
    /** If true, also copies to the output directory dependent shared libraries (link and preload). */
    boolean copyLibs = false;
    /** Accumulates the various properties loaded from resources, files, command line options, etc. */
    Properties properties = null;
    /** The instance of the {@link ClassScanner} that fills up a {@link Collection} of {@link Class} objects to process. */
    ClassScanner classScanner = null;
    /** User specified environment variables to pass to the native compiler. */
    Map environmentVariables = null;
    /** Contains additional command line options from the user for the native compiler. */
    Collection compilerOptions = null;

    /** Splits argument with {@link File#pathSeparator} and appends result to paths of the {@link #classScanner}. */
    public Builder classPaths(String classPaths) {
        classPaths(classPaths == null ? null : classPaths.split(File.pathSeparator));
        return this;
    }
    /** Appends argument to the paths of the {@link #classScanner}. */
    public Builder classPaths(String ... classPaths) {
        classScanner.getClassLoader().addPaths(classPaths);
        return this;
    }
    /** Sets the {@link #outputDirectory} field to the argument. */
    public Builder outputDirectory(String outputDirectory) {
        outputDirectory(outputDirectory == null ? null : new File(outputDirectory));
        return this;
    }
    /** Sets the {@link #outputDirectory} field to the argument. */
    public Builder outputDirectory(File outputDirectory) {
        this.outputDirectory = outputDirectory;
        return this;
    }
    /** Sets the {@link #compile} field to the argument. */
    public Builder compile(boolean compile) {
        this.compile = compile;
        return this;
    }
    /** Sets the {@link #deleteJniFiles} field to the argument. */
    public Builder deleteJniFiles(boolean deleteJniFiles) {
        this.deleteJniFiles = deleteJniFiles;
        return this;
    }
    /** Sets the {@link #header} field to the argument. */
    public Builder header(boolean header) {
        this.header = header;
        return this;
    }
    /** Sets the {@link #copyLibs} field to the argument. */
    public Builder copyLibs(boolean copyLibs) {
        this.copyLibs = copyLibs;
        return this;
    }
    /** Sets the {@link #outputName} field to the argument. */
    public Builder outputName(String outputName) {
        this.outputName = outputName;
        return this;
    }
    /** Sets the {@link #jarPrefix} field to the argument. */
    public Builder jarPrefix(String jarPrefix) {
        this.jarPrefix = jarPrefix;
        return this;
    }
    /** Sets the {@link #properties} field to the ones loaded from resources for the specified platform. */
    public Builder properties(String platform) {
        if (platform != null) {
            properties = Loader.loadProperties(platform, null);
        }
        return this;
    }
    /** Adds all the properties of the argument to the {@link #properties} field. */
    public Builder properties(Properties properties) {
        if (properties != null) {
            for (Map.Entry e : properties.entrySet()) {
                property((String)e.getKey(), (String)e.getValue());
            }
        }
        return this;
    }
    /** Sets the {@link #properties} field to the ones loaded from the specified file. */
    public Builder propertyFile(String filename) throws IOException {
        propertyFile(filename == null ? null : new File(filename));
        return this;
    }
    /** Sets the {@link #properties} field to the ones loaded from the specified file. */
    public Builder propertyFile(File propertyFile) throws IOException {
        if (propertyFile == null) {
            return this;
        }
        FileInputStream fis = new FileInputStream(propertyFile);
        properties = new Properties();
        try {
            properties.load(new InputStreamReader(fis));
        } catch (NoSuchMethodError e) {
            properties.load(fis);
        }
        fis.close();
        return this;
    }
    /** Sets a property of the {@link #properties} field, in either "key=value" or "key:value" format. */
    public Builder property(String keyValue) {
        int equalIndex = keyValue.indexOf('=');
        if (equalIndex < 0) {
            equalIndex = keyValue.indexOf(':');
        }
        property(keyValue.substring(2, equalIndex),
                 keyValue.substring(equalIndex+1));
        return this;
    }
    /** Sets a key/value pair property of the {@link #properties} field. */
    public Builder property(String key, String value) {
        if (key.length() > 0 && value.length() > 0) {
            properties.put(key, value);
        }
        return this;
    }
    /** Requests the {@link #classScanner} to add a class or all classes from a package.
     *  A {@code null} argument indicates the unnamed package. */
    public Builder classesOrPackages(String ... classesOrPackages) throws IOException, ClassNotFoundException, NoClassDefFoundError {
        if (classesOrPackages == null) {
            classScanner.addPackage(null, true);
        } else for (String s : classesOrPackages) {
            classScanner.addClassOrPackage(s);
        }
        return this;
    }
    /** Sets the {@link #environmentVariables} field to the argument. */
    public Builder environmentVariables(Map environmentVariables) {
        this.environmentVariables = environmentVariables;
        return this;
    }
    /** Appends arguments to the {@link #compilerOptions} field. */
    public Builder compilerOptions(String ... options) {
        if (options != null) {
            compilerOptions.addAll(Arrays.asList(options));
        }
        return this;
    }

    /**
     * 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 outputFiles = new ArrayList();
        Map> map = new LinkedHashMap>();
        for (Class c : classScanner.getClasses()) {
            if (Loader.getEnclosingClass(c) != c) {
                continue;
            }
            ClassProperties p = Loader.loadProperties(c, properties, false);
            if (!p.isLoaded()) {
                logger.warn("Could not load platform properties for " + c);
                continue;
            }
            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;
            }
            LinkedHashSet classList = map.get(libraryName);
            if (classList == null) {
                map.put(libraryName, classList = new LinkedHashSet());
            }
            classList.addAll(p.getEffectiveClasses());
        }
        for (String libraryName : map.keySet()) {
            LinkedHashSet classSet = map.get(libraryName);
            Class[] classArray = classSet.toArray(new Class[classSet.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 preloads = new ArrayList();
                    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, true);
                        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);
        }

        // reset the load flag to let users load compiled libraries
        System.setProperty("org.bytedeco.javacpp.loadlibraries", "true");
        return files;
    }

    /**
     * Simply prints out to the display the command line usage.
     */
    public static void printHelp() {
        String version = Builder.class.getPackage().getImplementationVersion();
        if (version == null) {
            version = "unknown";
        }
        System.out.println(
            "JavaCPP version " + version + "\n" +
            "Copyright (C) 2011-2016 Samuel Audet \n" +
            "Project site: https://github.com/bytedeco/javacpp");
        System.out.println();
        System.out.println("Usage: java -jar javacpp.jar [options] [class or package (suffixed with .* or .**)]");
        System.out.println();
        System.out.println("where options include:");
        System.out.println();
        System.out.println("    -classpath       Load user classes from path");
        System.out.println("    -d          Output all generated files to directory");
        System.out.println("    -o               Output everything in a file named after given name");
        System.out.println("    -nocompile             Do not compile or delete the generated source files");
        System.out.println("    -nodelete              Do not delete generated C++ JNI files after compilation");
        System.out.println("    -header                Generate header file with declarations of callbacks functions");
        System.out.println("    -copylibs              Copy to output directory dependent libraries (link and preload)");
        System.out.println("    -jarprefix     Also create a JAR file named \"-.jar\"");
        System.out.println("    -properties  Load all properties from resource");
        System.out.println("    -propertyfile    Load all properties from file");
        System.out.println("    -D=   Set property to value");
        System.out.println("    -Xcompiler 




© 2015 - 2024 Weber Informatics LLC | Privacy Policy