Răsfoiți Sursa

Merge topic 'UseJava-native-headers-generation'

4829ea23 add_jar: add option GENERATE_NATIVE_HEADERS

Acked-by: Kitware Robot <[email protected]>
Merge-request: !1675
Brad King 7 ani în urmă
părinte
comite
56fd8b3c72

+ 9 - 0
Help/release/dev/UseJava-add_jar-native-headers.rst

@@ -0,0 +1,9 @@
+UseJava-add_jar-native-headers
+------------------------------
+
+* | The command add_jar from :module:`UseJava` module learns how to generate native
+    headers files using option -h of javac tool.
+  | This capability requires, at least, version 1.8 of Javac tool.
+  | Command create_javah will no longer be supported due to the
+    `suppression of javah tool <http://openjdk.java.net/jeps/313>`_ in the version 1.10
+    of the JDK, so ``add_jar(GENERATE_NATIVE_HEADERS)`` must be used instead.

+ 73 - 1
Modules/UseJava.cmake

@@ -20,6 +20,7 @@
 #          [VERSION version]
 #          [OUTPUT_NAME name]
 #          [OUTPUT_DIR dir]
+#          [GENERATE_NATIVE_HEADERS target [DESTINATION dir]]
 #          )
 #
 # This command creates a <target_name>.jar.  It compiles the given
@@ -35,6 +36,14 @@
 # The default OUTPUT_DIR can also be changed by setting the variable
 # CMAKE_JAVA_TARGET_OUTPUT_DIR.
 #
+# Optionaly, using option GENERATE_NATIVE_HEADERS, native header files can be generated
+# for methods declared as native. These files provide the connective glue that allow your
+# Java and C code to interact. An INTERFACE target will be created for an easy usage
+# of generated files. Sub-option DESTINATION can be used to specify output directory for
+# generated header files.
+#
+# GENERATE_NATIVE_HEADERS option requires, at least, version 1.8 of the JDK.
+#
 # Additional instructions:
 #
 # ::
@@ -168,6 +177,22 @@
 #
 #
 #
+# ::
+#
+#     For an optimum usage of option GENERATE_NATIVE_HEADERS, it is recommended to
+#     include module JNI before any call to add_jar. The produced target for native
+#     headers can then be used to compile C/C++ sources with command
+#     target_link_libraries.
+#
+#
+# ::
+#
+#        find_package(JNI)
+#        add_jar(foo foo.java GENERATE_NATIVE_HEADERS foo-native)
+#        add_library(bar bar.cpp)
+#        target_link_libraries(bar PRIVATE foo-native)
+#
+#
 # Target Properties:
 #
 # ::
@@ -359,6 +384,10 @@
 # Create C header files from java classes. These files provide the connective glue
 # that allow your Java and C code to interact.
 #
+# This command will no longer be supported starting with version 1.10 of the JDK due
+# to the `suppression of javah tool <http://openjdk.java.net/jeps/313>`_.
+# Command ``add_jar(GENERATE_NATIVE_HEADERS)`` must be used instead.
+#
 # There are two main signatures for create_javah.  The first signature
 # returns generated files through variable specified by GENERATED_FILES option:
 #
@@ -448,7 +477,7 @@ function(add_jar _TARGET_NAME)
     cmake_parse_arguments(_add_jar
       ""
       "VERSION;OUTPUT_DIR;OUTPUT_NAME;ENTRY_POINT;MANIFEST"
-      "SOURCES;INCLUDE_JARS"
+      "SOURCES;INCLUDE_JARS;GENERATE_NATIVE_HEADERS"
       ${ARGN}
     )
 
@@ -494,6 +523,31 @@ function(add_jar _TARGET_NAME)
         get_filename_component (_MANIFEST_VALUE "${_add_jar_MANIFEST}" ABSOLUTE)
     endif ()
 
+    unset (_GENERATE_NATIVE_HEADERS)
+    if (_add_jar_GENERATE_NATIVE_HEADERS)
+      # Raise an error if JDK version is less than 1.8 because javac -h is not supported
+      # by earlier versions.
+      if ("${Java_VERSION}" VERSION_LESS 1.8)
+        message (FATAL_ERROR "ADD_JAR: GENERATE_NATIVE_HEADERS is not supported with this version of Java.")
+      endif()
+      cmake_parse_arguments (_add_jar_GENERATE_NATIVE_HEADERS "" "DESTINATION" "" ${_add_jar_GENERATE_NATIVE_HEADERS})
+      if (NOT _add_jar_GENERATE_NATIVE_HEADERS_UNPARSED_ARGUMENTS)
+        message (FATAL_ERROR "ADD_JAR: GENERATE_NATIVE_HEADERS: missing required argument.")
+      endif()
+      list (LENGTH _add_jar_GENERATE_NATIVE_HEADERS_UNPARSED_ARGUMENTS length)
+      if (length GREATER 1)
+        list (REMOVE_AT _add_jar_GENERATE_NATIVE_HEADERS_UNPARSED_ARGUMENTS 0)
+        message (FATAL_ERROR "ADD_JAR: GENERATE_NATIVE_HEADERS: ${_add_jar_GENERATE_NATIVE_HEADERS_UNPARSED_ARGUMENTS}: unexpected argument(s).")
+      endif()
+      if (NOT _add_jar_GENERATE_NATIVE_HEADERS_DESTINATION)
+        set (_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir/native_headers")
+      endif()
+
+      set (_GENERATE_NATIVE_HEADERS_TARGET ${_add_jar_GENERATE_NATIVE_HEADERS_UNPARSED_ARGUMENTS})
+      set (_GENERATE_NATIVE_HEADERS_OUTPUT_DIR "${_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION}")
+      set (_GENERATE_NATIVE_HEADERS -h "${_GENERATE_NATIVE_HEADERS_OUTPUT_DIR}")
+    endif()
+
     if (LIBRARY_OUTPUT_PATH)
         set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH})
     else ()
@@ -625,6 +679,7 @@ function(add_jar _TARGET_NAME)
                 ${CMAKE_JAVA_COMPILE_FLAGS}
                 -classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}"
                 -d ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
+                ${_GENERATE_NATIVE_HEADERS}
                 ${_JAVA_SOURCES_FILELISTS}
             COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
             DEPENDS ${_JAVA_COMPILE_FILES} ${_JAVA_COMPILE_FILELISTS} ${_JAVA_COMPILE_DEPENDS}
@@ -735,6 +790,17 @@ function(add_jar _TARGET_NAME)
                 ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
     )
 
+  if (_GENERATE_NATIVE_HEADERS)
+    # create an INTERFACE library encapsulating include directory for generated headers
+    add_library (${_GENERATE_NATIVE_HEADERS_TARGET} INTERFACE)
+    target_include_directories (${_GENERATE_NATIVE_HEADERS_TARGET} INTERFACE
+      "${_GENERATE_NATIVE_HEADERS_OUTPUT_DIR}"
+      ${JNI_INCLUDE_DIRS})
+    # this INTERFACE library depends on jar generation
+    add_dependencies (${_GENERATE_NATIVE_HEADERS_TARGET} ${_TARGET_NAME})
+
+    set_property (DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${_GENERATE_NATIVE_HEADERS_OUTPUT_DIR}")
+  endif()
 endfunction()
 
 function(INSTALL_JAR _TARGET_NAME)
@@ -1246,6 +1312,12 @@ function(create_javadoc _target)
 endfunction()
 
 function (create_javah)
+  if ("${Java_VERSION}" VERSION_GREATER_EQUAL 1.10)
+    message (FATAL_ERROR "create_javah: not supported with this Java version. Use add_jar(GENERATE_NATIVE_HEADERS) instead.")
+  elseif ("${Java_VERSION}" VERSION_GREATER_EQUAL 1.8)
+    message (DEPRECATION "create_javah: this command will no longer be supported starting with version 1.10 of JDK. Update your project by using command add_jar(GENERATE_NATIVE_HEADERS) instead.")
+  endif()
+
     cmake_parse_arguments(_create_javah
       ""
       "TARGET;GENERATED_FILES;OUTPUT_NAME;OUTPUT_DIR"

+ 38 - 16
Tests/CMakeLists.txt

@@ -3195,29 +3195,51 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
           --test-command ${JAVA_RUNTIME} -classpath hello3.jar HelloWorld)
         list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/JavaJarSourceListAndOutput")
 
-        # For next test, java tool must have same architecture as toolchain
+        # For next tests, java tool must have same architecture as toolchain
         math(EXPR _object_mode "${CMAKE_SIZEOF_VOID_P} * 8")
         execute_process(
           COMMAND "${Java_JAVA_EXECUTABLE}" -d${_object_mode} -version
           OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE _result
           )
         if(_result EQUAL 0)
-          if(_isMultiConfig)
-            set (JAVAH_LIBRARY_PATH ${CMake_BINARY_DIR}/Tests/JavaJavah/$<CONFIGURATION>)
-          else()
-            set (JAVAH_LIBRARY_PATH ${CMake_BINARY_DIR}/Tests/JavaJavah)
+          ## next test is valid only if Java version is less than 1.10
+          if ("${Java_VERSION}" VERSION_LESS 1.10)
+            if(_isMultiConfig)
+              set (JAVAH_LIBRARY_PATH ${CMake_BINARY_DIR}/Tests/JavaJavah/$<CONFIGURATION>)
+            else()
+              set (JAVAH_LIBRARY_PATH ${CMake_BINARY_DIR}/Tests/JavaJavah)
+            endif()
+            add_test(NAME Java.Javah COMMAND ${CMAKE_CTEST_COMMAND}
+              --build-and-test
+              "${CMake_SOURCE_DIR}/Tests/JavaJavah"
+              "${CMake_BINARY_DIR}/Tests/JavaJavah"
+              ${build_generator_args}
+              --build-project helloJavah
+              --build-two-config
+              --build-run-dir "${CMake_BINARY_DIR}/Tests/JavaJavah/"
+              --build-options ${build_options}
+              --test-command ${JAVA_RUNTIME} -Djava.library.path=${JAVAH_LIBRARY_PATH} -classpath hello3.jar HelloWorld2)
+            list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/JavaJavah")
+          endif()
+          ## next test is valid only if Java is, at least, version 1.8
+          if (NOT "${Java_VERSION}" VERSION_LESS 1.8)
+            if(_isMultiConfig)
+              set (JAVANATIVEHEADERS_LIBRARY_PATH ${CMake_BINARY_DIR}/Tests/JavaNativeHeaders/$<CONFIGURATION>)
+            else()
+              set (JAVANATIVEHEADERS_LIBRARY_PATH ${CMake_BINARY_DIR}/Tests/JavaNativeHeaders)
+            endif()
+            add_test(NAME Java.NativeHeaders COMMAND ${CMAKE_CTEST_COMMAND}
+              --build-and-test
+              "${CMake_SOURCE_DIR}/Tests/JavaNativeHeaders"
+              "${CMake_BINARY_DIR}/Tests/JavaNativeHeaders"
+              ${build_generator_args}
+              --build-project helloJavaNativeHeaders
+              --build-two-config
+              --build-run-dir "${CMake_BINARY_DIR}/Tests/JavaNativeHeaders/"
+              --build-options ${build_options}
+              --test-command ${JAVA_RUNTIME} -Djava.library.path=${JAVANATIVEHEADERS_LIBRARY_PATH} -classpath hello4.jar HelloWorld3)
+            list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/JavaNativeHeaders")
           endif()
-          add_test(NAME Java.Javah COMMAND ${CMAKE_CTEST_COMMAND}
-            --build-and-test
-            "${CMake_SOURCE_DIR}/Tests/JavaJavah"
-            "${CMake_BINARY_DIR}/Tests/JavaJavah"
-            ${build_generator_args}
-            --build-project helloJavah
-            --build-two-config
-            --build-run-dir "${CMake_BINARY_DIR}/Tests/JavaJavah/"
-            --build-options ${build_options}
-            --test-command ${JAVA_RUNTIME} -Djava.library.path=${JAVAH_LIBRARY_PATH} -classpath hello3.jar HelloWorld2)
-          list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/JavaJavah")
         endif()
       endif()
     endif()

+ 18 - 0
Tests/JavaNativeHeaders/CMakeLists.txt

@@ -0,0 +1,18 @@
+project(helloJavaNativeHeaders Java CXX)
+
+cmake_minimum_required (VERSION 2.6)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+find_package(Java COMPONENTS Development)
+include (UseJava)
+
+# JNI support
+find_package(JNI)
+
+add_jar(B1 D.java GENERATE_NATIVE_HEADERS D1-native)
+add_jar(E1 E.java GENERATE_NATIVE_HEADERS E1-native)
+
+add_jar(hello4 HelloWorld3.java)
+
+add_library(D SHARED D.cpp E.cpp)
+target_link_libraries (D PRIVATE D1-native E1-native)

+ 10 - 0
Tests/JavaNativeHeaders/D.cpp

@@ -0,0 +1,10 @@
+
+#include <jni.h>
+#include <stdio.h>
+
+#include "D.h"
+
+JNIEXPORT void JNICALL Java_D_printName(JNIEnv*, jobject)
+{
+  printf("D\n");
+}

+ 19 - 0
Tests/JavaNativeHeaders/D.java

@@ -0,0 +1,19 @@
+class D
+{
+  public D()
+    {
+    }
+
+    public native void printName();
+
+    static {
+        try {
+
+            System.loadLibrary("D");
+
+        } catch (UnsatisfiedLinkError e) {
+            System.err.println("Native code library failed to load.\n" + e);
+            System.exit(1);
+        }
+    }
+}

+ 10 - 0
Tests/JavaNativeHeaders/E.cpp

@@ -0,0 +1,10 @@
+
+#include <jni.h>
+#include <stdio.h>
+
+#include "E.h"
+
+JNIEXPORT void JNICALL Java_E_printName(JNIEnv*, jobject)
+{
+  printf("E\n");
+}

+ 19 - 0
Tests/JavaNativeHeaders/E.java

@@ -0,0 +1,19 @@
+class E
+{
+  public E()
+    {
+    }
+
+    public native void printName();
+
+    static {
+        try {
+
+            System.loadLibrary("D");
+
+        } catch (UnsatisfiedLinkError e) {
+            System.err.println("Native code library failed to load.\n" + e);
+            System.exit(1);
+        }
+    }
+}

+ 15 - 0
Tests/JavaNativeHeaders/HelloWorld3.java

@@ -0,0 +1,15 @@
+class HelloWorld3
+{
+    public static void main(String args[])
+    {
+        D d;
+        d = new D();
+        d.printName();
+
+        E e;
+        e = new E();
+        e.printName();
+
+        System.out.println("Hello World!");
+    }
+}