diff --git a/src/main/java/loci/jar2lib/FixProxies.java b/src/main/java/loci/jar2lib/FixProxies.java index 757c3f7..ac0bdd4 100644 --- a/src/main/java/loci/jar2lib/FixProxies.java +++ b/src/main/java/loci/jar2lib/FixProxies.java @@ -24,8 +24,8 @@ package loci.jar2lib; import java.io.BufferedReader; +import java.io.FileReader; import java.io.IOException; -import java.io.InputStreamReader; import java.util.ArrayList; /** @@ -65,8 +65,7 @@ public FixProxies(String conflictsFile) { // parse list of conflicting constants constants = new ArrayList(); - BufferedReader in = new BufferedReader(new InputStreamReader( - FixProxies.class.getResourceAsStream(conflictsFile))); + BufferedReader in = new BufferedReader(new FileReader(conflictsFile)); while (true) { String line = in.readLine(); if (line == null) break; diff --git a/src/main/java/loci/jar2lib/Jar2Lib.java b/src/main/java/loci/jar2lib/Jar2Lib.java index 98a323a..1338646 100644 --- a/src/main/java/loci/jar2lib/Jar2Lib.java +++ b/src/main/java/loci/jar2lib/Jar2Lib.java @@ -50,12 +50,10 @@ */ public class Jar2Lib { - // -- Constants -- - - public static final String DEFAULT_OUTPUT_DIR = "jar2lib-output"; - // -- Fields -- + private String projectId; + private String projectName; private List jarPaths; private String conflictsPath; private String headerPath; @@ -65,17 +63,56 @@ public class Jar2Lib { public Jar2Lib() { jarPaths = new ArrayList(); - outputPath = DEFAULT_OUTPUT_DIR; } // -- Jar2Lib methods -- + public String getProjectId() { + return projectId; + } + public void setProjectId(String projectId) { + this.projectId = projectId; + } + public String getProjectName() { + return projectName; + } + public void setProjectName(String projectName) { + this.projectName = projectName; + } + public List getLibraryPaths() { + return jarPaths; + } + public void setLibraryPaths(List jarPaths) { + this.jarPaths = jarPaths; + } + public String getConflictsPath() { + return conflictsPath; + } + public void setConflictsPath(String conflictsPath) { + this.conflictsPath = conflictsPath; + } + public String getHeaderPath() { + return headerPath; + } + public void setHeaderPath(String headerPath) { + this.headerPath = headerPath; + } + public String getOutputPath() { + return outputPath; + } + public void setOutputPath(String outputPath) { + this.outputPath = outputPath; + } + + /** Parses the settings from the given command line arguments. */ public void parseArgs(String[] args) { jarPaths = new ArrayList(); conflictsPath = null; headerPath = null; - outputPath = DEFAULT_OUTPUT_DIR; - for (int i = 0; i < args.length; i++) { + outputPath = null; + projectId = args.length >= 1 ? args[0] : null; + projectName = args.length >= 2 ? args[1] : null; + for (int i = 2; i < args.length; i++) { final String arg = args[i]; if (arg.equals("-conflicts")) { if (i == args.length - 1) die("Error: no conflicts file given."); @@ -92,15 +129,46 @@ else if (arg.equals("-output")) { else if (arg.startsWith("-")) die("Unknown flag: " + arg); else jarPaths.add(arg); } - if (jarPaths.size() == 0) { - die("Usage: java " + getClass().getName() + - " library.jar [library2.jar ...]\n" + - " [-conflicts conflicts.txt] [-header header.txt]\n" + - " [-output /path/to/output-project]"); + if (projectId == null || projectName == null || jarPaths.size() == 0) { + die("Usage: java " + getClass().getName() + " projectId projectName\n" + + " library.jar [library2.jar ...]\n" + + " [-conflicts conflicts.txt] [-header header.txt]\n" + + " [-output /path/to/output-project]"); } + if (outputPath == null) outputPath = projectId; } + /** Generates a C++ wrapper project based on the current settings. */ public void execute() throws IOException, VelocityException { + checkInputs(); + final File includeDir = generateFiles(); + copyResources(includeDir); + final File proxiesDir = generateProxies(includeDir); + fixConflicts(proxiesDir); + + // TODO - print instructions on how to proceed with CMake + // TODO - copy "final product" files such as wrapped JARs to build dir + + log("--> Done"); + } + + /** + * Checks that the current settings for project production are valid. + * Creates the output directory if it doesn't already exist. + * + * @throws IllegalStateException if the settings are invalid. + */ + public void checkInputs() { + // check project ID + if (projectId == null || !projectId.matches("^(\\w)+$")) { + throw new IllegalStateException("Invalid project ID: " + projectId); + } + + // check project name + if (projectName == null) { + throw new IllegalStateException("Invalid project name: " + projectName); + } + // check conflicts file if (conflictsPath != null && !new File(conflictsPath).exists()) { throw new IllegalStateException("Invalid conflicts file: " + @@ -118,34 +186,62 @@ public void execute() throws IOException, VelocityException { if (!outputDir.isDirectory()) { throw new IllegalStateException("Not a valid directory: " + outputPath); } + } + + /** + * Generates one header per input Java library. + * Also generates the CMake build file. + * + * @return The include path where headers were written. + */ + public File generateFiles() throws IOException, VelocityException { + final File outputDir = new File(outputPath); - // generate jace headers final VelocityAutogen generator = new VelocityAutogen(headerPath); final File includeDir = new File(outputPath, "include"); - if (!includeDir.exists()) includeDir.mkdirs(); + if (!includeDir.exists()) includeDir.mkdirs(); for (String jarPath : jarPaths) { - final File jarFile = new File(jarPath); + final File jarFile = new File(jarPath); log("--> Generating header for " + jarFile.getName()); generator.createJaceHeader(jarPath, path(includeDir)); } log("--> Generating CMake build file"); - final String projectId = "bfcpp"; //TODO TEMP! - final String projectName = "Bio-Formats C++ bindings"; //TODO TEMP! - generator.createCMakeLists(projectId, projectName, path(outputDir)); + generator.createCMakeLists(projectId, projectName, path(outputDir)); + + return includeDir; + } - // copy resources to output directory + /** + * Copies static project resources into the project directory. + * In particular, copies the Jace C++ distribution and related files. + * + * @param includeDir Folder containing the C++ headers. + */ + public void copyResources(File includeDir) throws IOException { + final File outputDir = new File(outputPath); log("--> Copying resources"); final List jaceResources = findResources("jace/"); for (String resource : jaceResources) copyResource(resource, outputDir); + copyResource("jace.h", includeDir); + } - // generate proxies using jace + /** + * Generates the C++ proxy classes enumerated in the C++ headers. + * + * @param includeDir Folder containing the C++ headers. + * @return The path where proxies were written. + * @throws UnsupportedEncodingException + */ + public File generateProxies(File includeDir) + throws UnsupportedEncodingException + { final File sourceDir = new File(outputPath, "source"); - if (!sourceDir.exists()) sourceDir.mkdirs(); + if (!sourceDir.exists()) sourceDir.mkdirs(); final File proxiesDir = new File(outputPath, "proxies"); final File proxiesIncludeDir = new File(proxiesDir, "include"); - if (!proxiesIncludeDir.exists()) proxiesIncludeDir.mkdirs(); + if (!proxiesIncludeDir.exists()) proxiesIncludeDir.mkdirs(); final File proxiesSourceDir = new File(proxiesDir, "source"); - if (!proxiesSourceDir.exists()) proxiesSourceDir.mkdirs(); + if (!proxiesSourceDir.exists()) proxiesSourceDir.mkdirs(); final String osName = System.getProperty("os.name"); final boolean isWindows = osName.indexOf("Windows") >= 0; final List autoProxyArgs = new ArrayList(); @@ -159,17 +255,21 @@ public void execute() throws IOException, VelocityException { log("--> Generating proxies"); AutoProxy.main(autoProxyArgs.toArray(new String[0])); - // post-process proxies to resolve any conflicts - if (conflictsPath != null) { - log("--> Renaming conflicting constants"); - final FixProxies fixProxies = new FixProxies(conflictsPath); - fixProxies.fixProxies(path(proxiesDir)); - } - - // TODO - print instructions on how to proceed with CMake - // TODO - copy "final product" files such as wrapped JARs to build dir + return proxiesDir; + } - log("--> Done"); + /** + * Post-processes the generated proxies to correct any + * conflicts identified in the specified conflicts file. + * + * @param proxiesDir Folder containing the generated C++ proxies. + * @throws IOException + */ + public void fixConflicts(File proxiesDir) throws IOException { + if (conflictsPath == null) return; + log("--> Renaming conflicting constants"); + final FixProxies fixProxies = new FixProxies(conflictsPath); + fixProxies.fixProxies(path(proxiesDir)); } // -- Main method -- @@ -221,6 +321,11 @@ private String classpath(List jarPaths) sb.append(":"); sb.append(jarPath); } + final String classPath = System.getProperty("java.class.path"); + if (classPath != null && !classPath.equals("")) { + sb.append(":"); + sb.append(classPath); + } return sb.toString(); } @@ -250,33 +355,35 @@ private List findResources(String resourceDir) throws IOException { private void copyResource(String resource, File baseDir) throws IOException { - log(resource); + log(resource); final File outputFile = new File(baseDir, resource); final File outputDir = outputFile.getParentFile(); if (!outputDir.exists()) outputDir.mkdirs(); - if (resource.endsWith("/")) { - // resource is a directory - outputFile.mkdir(); - } - else { - // resource is a file - final InputStream in = getClass().getResourceAsStream("/" + resource); - final OutputStream out = new FileOutputStream(outputFile); - final byte[] buf = new byte[512 * 1024]; // 512K buffer - while (true) { - int r = in.read(buf); - if (r <= 0) break; // EOF - out.write(buf, 0, r); - } - out.close(); - in.close(); - } + if (resource.endsWith("/")) { + // resource is a directory + outputFile.mkdir(); + } + else { + // resource is a file + final InputStream in = getClass().getResourceAsStream("/" + resource); + final OutputStream out = new FileOutputStream(outputFile); + final byte[] buf = new byte[512 * 1024]; // 512K buffer + while (true) { + int r = in.read(buf); + if (r <= 0) break; // EOF + out.write(buf, 0, r); + } + out.close(); + in.close(); + } } - /** - * Finds the JAR file (or file system path) - * from which the given class was loaded. - */ + // -- Static utility methods -- + + /** + * Finds the JAR file (or file system path) + * from which the given class was loaded. + */ public static String findEnclosingJar(Class c) throws UnsupportedEncodingException { diff --git a/src/main/resources/CMakeLists.vm b/src/main/resources/CMakeLists.vm index 0ea17cb..0367139 100644 --- a/src/main/resources/CMakeLists.vm +++ b/src/main/resources/CMakeLists.vm @@ -12,20 +12,9 @@ include(jace/Prerequisites.cmake) add_subdirectory(jace) -# TODO - eliminate use of JACE_DIR since we are bundling the source directly -#message(STATUS "-- Jace:") -\#set(JACE_DIR NOTFOUND CACHE PATH -# "The path to toplevel directory of your Jace checkout") -\#if(IS_DIRECTORY "${JACE_DIR}") -# message(STATUS "jace root : ${JACE_DIR}") -\#else(IS_DIRECTORY "${JACE_DIR}") -# message(FATAL_ERROR "Cannot build without Jace. Please set JACE_DIR.") -#endif(IS_DIRECTORY "${JACE_DIR}") - # -- build $projectName -- -include_directories(include - "proxies/include" "${JACE_CPP_DIR}/include" +include_directories(include "proxies/include" "jace/include" "${JAVA_INCLUDE_PATH}" "${JAVA_INCLUDE_PATH2}" "${Boost_INCLUDE_DIR}") file(GLOB_RECURSE PROJECT_SRC "proxies/source/*.cpp") diff --git a/src/main/resources/jace.h b/src/main/resources/jace.h new file mode 100644 index 0000000..4802aff --- /dev/null +++ b/src/main/resources/jace.h @@ -0,0 +1,82 @@ +// +// jace.h +// + +#ifndef JACE_H +#define JACE_H + +#include "jace/JNIHelper.h" + +#include "jace/JArray.h" +#include "jace/JNIException.h" +#include "jace/OptionList.h" +#include "jace/StaticVmLoader.h" +//using namespace jace; + +#include "jace/proxy/types/JBoolean.h" +#include "jace/proxy/types/JByte.h" +#include "jace/proxy/types/JChar.h" +#include "jace/proxy/types/JDouble.h" +#include "jace/proxy/types/JFloat.h" +#include "jace/proxy/types/JInt.h" +#include "jace/proxy/types/JLong.h" +#include "jace/proxy/types/JShort.h" +#include "jace/proxy/types/JVoid.h" +//using namespace jace::proxy::types; + +typedef jace::JArray BooleanArray; +typedef jace::JArray BooleanArray2D; +typedef jace::JArray BooleanArray3D; +typedef jace::JArray BooleanArray4D; +typedef jace::JArray ByteArray; +typedef jace::JArray ByteArray2D; +typedef jace::JArray ByteArray3D; +typedef jace::JArray ByteArray4D; +typedef jace::JArray CharArray; +typedef jace::JArray CharArray2D; +typedef jace::JArray CharArray3D; +typedef jace::JArray CharArray4D; +typedef jace::JArray DoubleArray; +typedef jace::JArray DoubleArray2D; +typedef jace::JArray DoubleArray3D; +typedef jace::JArray DoubleArray4D; +typedef jace::JArray FloatArray; +typedef jace::JArray FloatArray2D; +typedef jace::JArray FloatArray3D; +typedef jace::JArray FloatArray4D; +typedef jace::JArray IntArray; +typedef jace::JArray IntArray2D; +typedef jace::JArray IntArray3D; +typedef jace::JArray IntArray4D; +typedef jace::JArray LongArray; +typedef jace::JArray LongArray2D; +typedef jace::JArray LongArray3D; +typedef jace::JArray LongArray4D; +typedef jace::JArray ShortArray; +typedef jace::JArray ShortArray2D; +typedef jace::JArray ShortArray3D; +typedef jace::JArray ShortArray4D; + +#include "jace/proxy/java/lang/Boolean.h" +#include "jace/proxy/java/lang/Byte.h" +#include "jace/proxy/java/lang/Character.h" +#include "jace/proxy/java/lang/Double.h" +#include "jace/proxy/java/lang/Float.h" +#include "jace/proxy/java/lang/Integer.h" +#include "jace/proxy/java/lang/Long.h" +#include "jace/proxy/java/lang/Short.h" +#include "jace/proxy/java/lang/String.h" +//using namespace jace::proxy::java::lang; + +typedef jace::JArray StringArray; +typedef jace::JArray StringArray2D; +typedef jace::JArray StringArray3D; +typedef jace::JArray StringArray4D; + +#include "jace/proxy/java/io/IOException.h" +//using namespace jace::proxy::java::io; + +#include "jace/proxy/java/util/Hashtable.h" +//using namespace jace::proxy::java::util; + +#endif diff --git a/src/main/resources/jace/CMakeLists.txt b/src/main/resources/jace/CMakeLists.txt index 90e1001..7deba09 100644 --- a/src/main/resources/jace/CMakeLists.txt +++ b/src/main/resources/jace/CMakeLists.txt @@ -12,22 +12,11 @@ include(Prerequisites.cmake) ### build Jace C++ library ### -#message(STATUS "-- Jace:") -#set(JACE_DIR NOTFOUND CACHE PATH -# "The path to toplevel directory of your Jace checkout") -#if(IS_DIRECTORY "${JACE_DIR}") -# message(STATUS "jace root : ${JACE_DIR}") -#else(IS_DIRECTORY "${JACE_DIR}") -# message(FATAL_ERROR "Cannot build without Jace. Please set JACE_DIR.") -#endif(IS_DIRECTORY "${JACE_DIR}") - -include_directories("${JACE_CPP_DIR}/include" +include_directories("include" "${JAVA_INCLUDE_PATH}" "${JAVA_INCLUDE_PATH2}" "${Boost_INCLUDE_DIR}") -file(GLOB_RECURSE JACE_SRC "${JACE_CPP_DIR}/source/*.cpp") -#message("jace source : ${JACE_SRC}") -message(STATUS "") +file(GLOB_RECURSE JACE_SRC "source/*.cpp") add_library(jace SHARED ${JACE_SRC}) diff --git a/src/main/resources/jace/Prerequisites.cmake b/src/main/resources/jace/Prerequisites.cmake index 073c42e..69846d4 100644 --- a/src/main/resources/jace/Prerequisites.cmake +++ b/src/main/resources/jace/Prerequisites.cmake @@ -71,16 +71,3 @@ message(STATUS "") if(WIN32) link_directories(${Boost_STRIPPED_LIB_DIR}) endif(WIN32) - -message(STATUS "-- Jace:") -set(JACE_DIR NOTFOUND CACHE PATH - "The path to toplevel directory of your Jace checkout") -if(IS_DIRECTORY "${JACE_DIR}") - message(STATUS "jace root : ${JACE_DIR}") -else(IS_DIRECTORY "${JACE_DIR}") - message(FATAL_ERROR "Cannot build without Jace. Please set JACE_DIR.") -endif(IS_DIRECTORY "${JACE_DIR}") - -set(JACE_CPP_DIR "${JACE_DIR}/source/c++") -# For Jace r46 and later, use instead (& see build.properties): -#set(JACE_CPP_DIR "${JACE_DIR}/core/cpp")