Browse Source

Merge topic 'java-export-targets'

0bd91ad4 UseJava: Fix race condition creating java class list
89df91b9 Help: Add notes for topic 'java-export-targets'
95d84369 Tests: Add test for exported JARs
5341c0d8 UseJava: Add infrastructure to export targets
d91ec044 Tests/Java: Clean up style of Java test code
Brad King 9 years ago
parent
commit
5aa89a1ae0

+ 6 - 0
Help/release/dev/java-export-targets.rst

@@ -0,0 +1,6 @@
+java-export-targets
+-------------------
+
+* The :module:`UseJava` module gained APIs to "export" jar targets
+  for use by external CMake projects.  See the ``install_jar_exports``
+  and ``export_jars`` functions.

+ 158 - 5
Modules/UseJava.cmake

@@ -217,6 +217,19 @@
 # This command installs the TARGET_NAME files to the given DESTINATION.
 # It should be called in the same scope as add_jar() or it will fail.
 #
+# Target Properties:
+#
+# ::
+#
+#    The install_jar() function sets the INSTALL_DESTINATION target property
+#    on jars so installed. This property holds the DESTINATION as described
+#    above, and is used by install_jar_exports(). You can get this property
+#    with the
+#       get_property(TARGET <target_name> PROPERTY INSTALL_DESTINATION)
+#    command.
+#
+#
+#
 # ::
 #
 #  install_jni_symlink(target_name destination)
@@ -228,6 +241,24 @@
 #
 # ::
 #
+#  install_jar_exports(TARGETS jar1 [jar2 ...]
+#                      FILE export_filename
+#                      DESTINATION destination [COMPONENT component])
+#
+# This command installs a target export file export_filename for the named jar
+# targets to the given DESTINATION. Its function is similar to that of
+# install(EXPORTS).
+#
+# ::
+#
+#  export_jars(TARGETS jar1 [jar2 ...]
+#              FILE export_filename)
+#
+# This command writes a target export file export_filename for the named jar
+# targets. Its function is similar to that of export().
+#
+# ::
+#
 #  create_javadoc(<VAR>
 #                 PACKAGES pkg1 [pkg2 ...]
 #                 [SOURCEPATH <sourcepath>]
@@ -396,7 +427,29 @@ function (__java_copy_file src dest comment)
         COMMENT ${comment})
 endfunction ()
 
+function(__java_lcat VAR)
+    foreach(_line ${ARGN})
+        set(${VAR} "${${VAR}}${_line}\n")
+    endforeach()
+
+    set(${VAR} "${${VAR}}" PARENT_SCOPE)
+endfunction()
+
+function(__java_export_jar VAR TARGET PATH)
+    get_target_property(_jarpath ${TARGET} JAR_FILE)
+    get_filename_component(_jarname ${_jarpath} NAME)
+    __java_lcat(${VAR}
+      "# Create imported target ${TARGET}"
+      "add_custom_target(${TARGET})"
+      "set_target_properties(${TARGET} PROPERTIES"
+      "  JAR_FILE \"${PATH}/${_jarname}\")"
+      ""
+    )
+    set(${VAR} "${${VAR}}" PARENT_SCOPE)
+endfunction()
+
 # define helper scripts
+set(_JAVA_EXPORT_TARGETS_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/javaTargets.cmake.in)
 set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaClassFilelist.cmake)
 set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaSymlinks.cmake)
 
@@ -435,6 +488,8 @@ function(add_jar _TARGET_NAME)
 
     if (NOT DEFINED _add_jar_OUTPUT_DIR)
         set(_add_jar_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
+    else()
+        get_filename_component(_add_jar_OUTPUT_DIR ${_add_jar_OUTPUT_DIR} ABSOLUTE)
     endif()
 
     if (_add_jar_ENTRY_POINT)
@@ -554,11 +609,6 @@ function(add_jar _TARGET_NAME)
         endif ()
     endforeach()
 
-    # create an empty java_class_filelist
-    if (NOT EXISTS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist)
-        file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "")
-    endif()
-
     if (_JAVA_COMPILE_FILES OR _JAVA_COMPILE_FILELISTS)
         set (_JAVA_SOURCES_FILELISTS)
 
@@ -598,6 +648,11 @@ function(add_jar _TARGET_NAME)
             DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
         )
+    else ()
+        # create an empty java_class_filelist
+        if (NOT EXISTS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist)
+            file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "")
+        endif()
     endif ()
 
     # create the jar file
@@ -716,6 +771,13 @@ function(INSTALL_JAR _TARGET_NAME)
         PROPERTY
             INSTALL_FILES
     )
+    set_property(
+        TARGET
+            ${_TARGET_NAME}
+        PROPERTY
+            INSTALL_DESTINATION
+            ${_DESTINATION}
+    )
 
     if (__FILES)
         install(
@@ -1288,3 +1350,94 @@ function (create_javah)
       set (${_create_javah_GENERATED_FILES} ${_output_files} PARENT_SCOPE)
     endif()
 endfunction()
+
+function(export_jars)
+    # Parse and validate arguments
+    cmake_parse_arguments(_export_jars
+      ""
+      "FILE"
+      "TARGETS"
+      ${ARGN}
+    )
+    if (NOT _export_jars_FILE)
+      message(SEND_ERROR "export_jars: FILE must be specified.")
+    endif()
+    if (NOT _export_jars_TARGETS)
+      message(SEND_ERROR "export_jars: TARGETS must be specified.")
+    endif()
+
+    # Set content of generated exports file
+    string(REPLACE ";" " " __targets__ "${_export_jars_TARGETS}")
+    set(__targetdefs__ "")
+    foreach(_target ${_export_jars_TARGETS})
+        get_target_property(_jarpath ${_target} JAR_FILE)
+        get_filename_component(_jarpath ${_jarpath} PATH)
+        __java_export_jar(__targetdefs__ ${_target} "${_jarpath}")
+    endforeach()
+
+    # Generate exports file
+    configure_file(
+      ${_JAVA_EXPORT_TARGETS_SCRIPT}
+      ${_export_jars_FILE}
+      @ONLY
+    )
+endfunction()
+
+function(install_jar_exports)
+    # Parse and validate arguments
+    cmake_parse_arguments(_install_jar_exports
+      ""
+      "FILE;DESTINATION;COMPONENT"
+      "TARGETS"
+      ${ARGN}
+    )
+    if (NOT _install_jar_exports_FILE)
+      message(SEND_ERROR "install_jar_exports: FILE must be specified.")
+    endif()
+    if (NOT _install_jar_exports_DESTINATION)
+      message(SEND_ERROR "install_jar_exports: DESTINATION must be specified.")
+    endif()
+    if (NOT _install_jar_exports_TARGETS)
+      message(SEND_ERROR "install_jar_exports: TARGETS must be specified.")
+    endif()
+
+    if (_install_jar_exports_COMPONENT)
+      set (_COMPONENT COMPONENT ${_install_jar_exports_COMPONENT})
+    endif()
+
+    # Determine relative path from installed export file to install prefix
+    if(IS_ABSOLUTE ${_install_jar_exports_DESTINATION})
+      file(RELATIVE_PATH _relpath
+        ${_install_jar_exports_DESTINATION}
+        ${CMAKE_INSTALL_PREFIX}
+      )
+    else()
+      file(RELATIVE_PATH _relpath
+        ${CMAKE_INSTALL_PREFIX}/${_install_jar_exports_DESTINATION}
+        ${CMAKE_INSTALL_PREFIX}
+      )
+    endif()
+
+    # Set up unique location for generated exports file
+    string(SHA256 _hash "${_install_jar_exports_DESTINATION}")
+    set(_tmpdir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/JavaExports/${_hash})
+
+    # Set content of generated exports file
+    string(REPLACE ";" " " __targets__ "${_install_jar_exports_TARGETS}")
+    set(__targetdefs__ "set(_prefix \${CMAKE_CURRENT_LIST_DIR}/${_relpath})\n\n")
+    foreach(_target ${_install_jar_exports_TARGETS})
+        get_target_property(_dir ${_target} INSTALL_DESTINATION)
+        __java_export_jar(__targetdefs__ ${_target} "\${_prefix}/${_dir}")
+    endforeach()
+    __java_lcat(__targetdefs__ "\nunset(_prefix)")
+
+    # Generate and install exports file
+    configure_file(
+      ${_JAVA_EXPORT_TARGETS_SCRIPT}
+      ${_tmpdir}/${_install_jar_exports_FILE}
+      @ONLY
+    )
+    install(FILES ${_tmpdir}/${_install_jar_exports_FILE}
+            DESTINATION ${_install_jar_exports_DESTINATION}
+            ${_COMPONENT})
+endfunction()

+ 39 - 0
Modules/javaTargets.cmake.in

@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 2.8)
+cmake_policy(PUSH)
+cmake_policy(VERSION 2.8)
+
+#----------------------------------------------------------------
+# Generated CMake Java target import file.
+#----------------------------------------------------------------
+
+# Protect against multiple inclusion, which would fail when already imported targets are added once more.
+set(_targetsDefined)
+set(_targetsNotDefined)
+set(_expectedTargets)
+foreach(_expectedTarget @__targets__@)
+  list(APPEND _expectedTargets ${_expectedTarget})
+  if(TARGET ${_expectedTarget})
+    list(APPEND _targetsDefined ${_expectedTarget})
+  else()
+    list(APPEND _targetsNotDefined ${_expectedTarget})
+  endif()
+endforeach()
+if("%${_targetsDefined}" STREQUAL "%${_expectedTargets}")
+  unset(_targetsDefined)
+  unset(_targetsNotDefined)
+  unset(_expectedTargets)
+  cmake_policy(POP)
+  return()
+endif()
+if(NOT "${_targetsDefined}" STREQUAL "")
+  message(FATAL_ERROR
+    "Some (but not all) targets in this export set were already defined.\n"
+    "Targets Defined: ${_targetsDefined}\n"
+    "Targets not yet defined: ${_targetsNotDefined}\n")
+endif()
+unset(_targetsDefined)
+unset(_targetsNotDefined)
+unset(_expectedTargets)
+
+@__targetdefs__@
+cmake_policy(POP)

+ 4 - 0
Tests/CMakeLists.txt

@@ -3108,6 +3108,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
   find_package(Java COMPONENTS Development QUIET)
   if(Java_JAVA_EXECUTABLE AND Java_JAVAC_EXECUTABLE AND Java_JAR_EXECUTABLE AND NOT MINGW
       AND NOT "${CMAKE_GENERATOR}" MATCHES "Xcode")
+
+    set(JavaExportImport_BUILD_OPTIONS -DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM})
+    ADD_TEST_MACRO(JavaExportImport JavaExportImport)
+
     get_filename_component(JNIPATH ${JAVA_COMPILE} PATH)
     find_file(JNI_H jni.h
       "${JNIPATH}/../include"

+ 5 - 5
Tests/Java/A.java

@@ -1,11 +1,11 @@
 class A
 {
   public A()
-    {
-    }
+  {
+  }
 
   public void printName()
-    {
-      System.out.println("A");
-    }
+  {
+    System.out.println("A");
+  }
 }

+ 7 - 7
Tests/Java/HelloWorld.java

@@ -1,11 +1,11 @@
 class HelloWorld
 {
-    public static void main(String args[])
-    {
-        A a;
-        a = new A();
-        a.printName();
-        System.out.println("Hello World!");
-    }
+  public static void main(String args[])
+  {
+    A a;
+    a = new A();
+    a.printName();
+    System.out.println("Hello World!");
+  }
 }
 

+ 10 - 0
Tests/JavaExportImport/BuildExport/CMakeLists.txt

@@ -0,0 +1,10 @@
+project(foo Java)
+
+cmake_minimum_required (VERSION 3.5)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+find_package(Java COMPONENTS Development)
+include(UseJava)
+
+add_jar(${PROJECT_NAME} Foo.java)
+export_jars(TARGETS ${PROJECT_NAME} FILE JavaBuildExportTestConfig.cmake)

+ 11 - 0
Tests/JavaExportImport/BuildExport/Foo.java

@@ -0,0 +1,11 @@
+class Foo
+{
+  public Foo()
+  {
+  }
+
+  public void printName()
+  {
+    System.out.println("Foo");
+  }
+}

+ 104 - 0
Tests/JavaExportImport/CMakeLists.txt

@@ -0,0 +1,104 @@
+cmake_minimum_required (VERSION 3.5)
+project(JavaExportImport)
+if(NOT DEFINED CMake_TEST_NESTED_MAKE_PROGRAM AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+  set(CMake_TEST_NESTED_MAKE_PROGRAM "${CMAKE_MAKE_PROGRAM}")
+endif()
+
+find_package(Java COMPONENTS Development)
+
+# Wipe out the install tree to make sure the exporter works.
+add_custom_command(
+  OUTPUT ${JavaExportImport_BINARY_DIR}/CleanupProject
+  COMMAND ${CMAKE_COMMAND} -E remove_directory ${JavaExportImport_BINARY_DIR}/Root
+  )
+add_custom_target(CleanupTarget ALL DEPENDS ${JavaExportImport_BINARY_DIR}/CleanupProject)
+set_property(
+  SOURCE ${JavaExportImport_BINARY_DIR}/CleanupProject
+  PROPERTY SYMBOLIC 1
+  )
+
+if(CMAKE_CONFIGURATION_TYPES)
+  set(NESTED_CONFIG_TYPE -C "${CMAKE_CFG_INTDIR}")
+else()
+  if(CMAKE_BUILD_TYPE)
+    set(NESTED_CONFIG_TYPE -C "${CMAKE_BUILD_TYPE}")
+  else()
+    set(NESTED_CONFIG_TYPE)
+  endif()
+endif()
+
+configure_file(${JavaExportImport_SOURCE_DIR}/InitialCache.cmake.in
+               ${JavaExportImport_BINARY_DIR}/InitialCache.cmake @ONLY)
+
+# Build the build exporter.
+add_custom_command(
+  OUTPUT ${JavaExportImport_BINARY_DIR}/BuildExportProject
+  COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+    --build-and-test
+    ${JavaExportImport_SOURCE_DIR}/BuildExport
+    ${JavaExportImport_BINARY_DIR}/BuildExport
+    --build-noclean
+    --build-project BuildExport
+    --build-generator ${CMAKE_GENERATOR}
+    --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+    --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+    --build-options -C${JavaExportImport_BINARY_DIR}/InitialCache.cmake
+  VERBATIM
+  )
+add_custom_target(BuildExportTarget ALL DEPENDS ${JavaExportImport_BINARY_DIR}/BuildExportProject)
+add_dependencies(BuildExportTarget CleanupTarget)
+set_property(
+  SOURCE ${JavaExportImport_BINARY_DIR}/BuildExportProject
+  PROPERTY SYMBOLIC 1
+  )
+
+# Build and install the install exporter.
+add_custom_command(
+  OUTPUT ${JavaExportImport_BINARY_DIR}/InstallExportProject
+  COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+    --build-and-test
+    ${JavaExportImport_SOURCE_DIR}/InstallExport
+    ${JavaExportImport_BINARY_DIR}/InstallExport
+    --build-noclean
+    --build-project InstallExport
+    --build-target install
+    --build-generator ${CMAKE_GENERATOR}
+    --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+    --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+    --build-options -C${JavaExportImport_BINARY_DIR}/InitialCache.cmake
+  VERBATIM
+  )
+add_custom_target(InstallExportTarget ALL DEPENDS ${JavaExportImport_BINARY_DIR}/InstallExportProject)
+add_dependencies(InstallExportTarget CleanupTarget)
+set_property(
+  SOURCE ${JavaExportImport_BINARY_DIR}/InstallExportProject
+  PROPERTY SYMBOLIC 1
+  )
+
+# Build and install the importer.
+add_custom_command(
+  OUTPUT ${JavaExportImport_BINARY_DIR}/ImportProject
+  COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+    --build-and-test
+    ${JavaExportImport_SOURCE_DIR}/Import
+    ${JavaExportImport_BINARY_DIR}/Import
+    --build-noclean
+    --build-project Import
+    --build-generator ${CMAKE_GENERATOR}
+    --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+    --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+    --build-options
+      -C${JavaExportImport_BINARY_DIR}/InitialCache.cmake
+      -DJavaBuildExportTest_DIR:PATH=${JavaExportImport_BINARY_DIR}/BuildExport
+      -DJavaInstallExportTest_DIR:PATH=${JavaExportImport_BINARY_DIR}/Root/share/cmake
+  VERBATIM
+  )
+add_custom_target(ImportTarget ALL DEPENDS ${JavaExportImport_BINARY_DIR}/ImportProject)
+add_dependencies(ImportTarget BuildExportTarget InstallExportTarget)
+set_property(
+  SOURCE ${JavaExportImport_BINARY_DIR}/ImportProject
+  PROPERTY SYMBOLIC 1
+  )
+
+add_executable(JavaExportImport main.c)
+add_dependencies(JavaExportImport ImportTarget)

+ 14 - 0
Tests/JavaExportImport/Import/CMakeLists.txt

@@ -0,0 +1,14 @@
+project(import Java)
+
+cmake_minimum_required (VERSION 3.5)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+find_package(Java COMPONENTS Development)
+include(UseJava)
+
+find_package(JavaBuildExportTest REQUIRED)
+find_package(JavaInstallExportTest REQUIRED)
+
+add_jar(${PROJECT_NAME}
+  SOURCES Import.java
+  INCLUDE_JARS foo bar)

+ 10 - 0
Tests/JavaExportImport/Import/Import.java

@@ -0,0 +1,10 @@
+class Import
+{
+  public static void main(String args[])
+  {
+    Foo foo = new Foo();
+    Bar bar = new Bar();
+    foo.printName();
+    bar.printName();
+  }
+}

+ 5 - 0
Tests/JavaExportImport/InitialCache.cmake.in

@@ -0,0 +1,5 @@
+set(CMAKE_MAKE_PROGRAM "@CMake_TEST_NESTED_MAKE_PROGRAM@" CACHE FILEPATH "Make Program")
+set(Java_JAVA_EXECUTABLE "@Java_JAVA_EXECUTABLE@" CACHE STRING "Java Interpreter")
+set(Java_JAVAC_EXECUTABLE "@Java_JAVAC_EXECUTABLE@" CACHE STRING "Java Compiler")
+set(Java_JAR_EXECUTABLE "@Java_JAR_EXECUTABLE@" CACHE STRING "Java Archive Tool")
+set(CMAKE_INSTALL_PREFIX "@JavaExportImport_BINARY_DIR@/Root" CACHE STRING "Installation Prefix")

+ 11 - 0
Tests/JavaExportImport/InstallExport/Bar.java

@@ -0,0 +1,11 @@
+class Bar
+{
+  public Bar()
+  {
+  }
+
+  public void printName()
+  {
+    System.out.println("Bar");
+  }
+}

+ 14 - 0
Tests/JavaExportImport/InstallExport/CMakeLists.txt

@@ -0,0 +1,14 @@
+project(bar Java)
+
+cmake_minimum_required (VERSION 3.5)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+find_package(Java COMPONENTS Development)
+include(UseJava)
+
+add_jar(${PROJECT_NAME} Bar.java)
+install_jar(${PROJECT_NAME} DESTINATION share/java)
+install_jar_exports(
+  TARGETS ${PROJECT_NAME}
+  FILE JavaInstallExportTestConfig.cmake
+  DESTINATION share/cmake)

+ 4 - 0
Tests/JavaExportImport/main.c

@@ -0,0 +1,4 @@
+int main()
+{
+  return 0;
+}