Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct way to use add_jar with Java bindings produced by Swig?

Tags:

java

cmake

swig

I am using Swig to produce a Java binding for a C library. The build system is written in CMake in order to achieve platform neutrality. I wish to produce a JAR file containing the Java bindings (i.e. the .class files resulting from the compilation of the .java files created by Swig). I am trying to use the Cmake add_jar() command to perform the compilation and produce the JAR file.

My problem is that Swig produces a set of Java files at build time, but add_jar() requires a list of source files at the time cmake is executed. I am currently working around the problem using a UNIX wildcard (which is passed literally to the javac command line).

# How do I avoid the shell wildcard?
add_jar(ExampleJNI ${CMAKE_SWIG_OUTDIR}/*.java)

Is there a better way?

I include below a complete example (comprising of three files) that illustrates my approach. If you want to try for yourself, put the three files in a directory, then invoke cmake . ; make VERBOSE=1.

CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
find_package(Swig REQUIRED)
find_package(Java REQUIRED)
find_package(JNI REQUIRED)
include(UseJava)
include(UseSWIG)

project (Example)

add_library (Example example.c)

set(CMAKE_SWIG_FLAGS -package org.mycompany)
set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}/src/main/java/org/mycompany)

swig_add_module(ExampleSWIG java example.i)
include_directories(${JNI_INCLUDE_DIRS})

swig_link_libraries(ExampleSWIG Example)

# How do I avoid the wildcard?
add_jar(ExampleJNI ${CMAKE_SWIG_OUTDIR}/*.java)

add_dependencies(ExampleJNI ExampleSWIG)

example.c

int foo() {
  return 0;
}

example.i

%module example

%inline %{
    extern int    foo();
%}

I am using:

  • cmake version 2.8.10.2
  • Java version "1.6.0_37"
  • SWIG Version 2.0.9
  • Mac OS X Darwin Kernel Version 12.2.0
like image 780
k-wall Avatar asked Jan 26 '13 23:01

k-wall


1 Answers

This post is old but I had the same problem today and found a nice solution.

My current approach distinguish between buildsystem generation time and build-time. Instead of using wildcards (what does not seem to work with add_jar on windows). I use add_custom_command() to generate a JAR with the generated java classes at build-time. I know the name of this JAR at buildsystem generation time. And so i can use the name as INCLUDE_JAR parameter for add_jar() function. I will refer to the JAR containing the java files generated by SWIG as Native.jar.

Here is a example how you can achieve CMake + Java + SWIG

First we need to find the necessary packages:

FIND_PACKAGE(SWIG REQUIRED)
FIND_PACKAGE(JNI REQUIRED)
FIND_PACKAGE(Java REQUIRED)
INCLUDE(UseSWIG)
INCLUDE(UseJava)

Then we need to define our SWIG Module:

SET(CMAKE_SWIG_OUTDIR "${CMAKE_CURRENT_BINARY_DIR}/java")
SET_PROPERTY(SOURCE "native-interface.i" PROPERTY CPLUSPLUS ON)
SWIG_ADD_MODULE(Native java "native-interface.i" 
    "algorithm.hpp"
    "algorithm-listener.hpp"
    "simple-methods.hpp" "simple-methods.cpp"
    )
TARGET_INCLUDE_DIRECTORIES(Native
    PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
    PRIVATE ${JAVA_INCLUDE_PATH}
    PRIVATE ${JAVA_INCLUDE_PATH2})

As you can see I use a java subdirectory to store the java files. I will also add a subdirectory for class files and then register POST_BUILD Events to build the Native.jar:

FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/classes")
ADD_CUSTOM_COMMAND(TARGET Native POST_BUILD
    COMMAND "${Java_JAVAC_EXECUTABLE}" -d classes java/*.java
    COMMAND "${Java_JAR_EXECUTABLE}" -cfM Native.jar -C classes .
    )
# Store Path to native JAR in variable:
SET(NATIVE_JAR "${CMAKE_CURRENT_BINARY_DIR}/Native.jar")

In the next step we will generate a java project using add_jar() function:

ADD_JAR(ConsoleApp 
    SOURCES "NativeInvoker.java"
    INCLUDE_JARS ${NATIVE_JAR})
SET(CMAKE_JAVA_COMPILE_FLAGS "-source" "1.8" "-target" "1.8")

If you use different folder for your project (like have native in one subdirectory and java stuff in another). You must copy the Native.dll to the same folder like your java application or ensure that it is found by Java. To do this in CMake u can use add_custom_command() again.

ADD_CUSTOM_COMMAND(TARGET ConsoleApp POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Native> ${CMAKE_CURRENT_BINARY_DIR})

Hope this is helpful for a lot of you guys.

Greetings Tim

like image 91
DarthB Avatar answered Oct 15 '22 00:10

DarthB