Pārlūkot izejas kodu

UseJava: add INCLUDE_MODULES argument to add_jar

Arguments are added to the dependencies list, and to the "--module-path"
passed to javac, which is only generated for adequate JDK versions.
Javier Martín 3 nedēļas atpakaļ
vecāks
revīzija
343ee5b9ee

+ 7 - 0
Help/release/dev/UseJava-include-modules.rst

@@ -0,0 +1,7 @@
+UseJava-include-modules
+-----------------------
+
+* The :module:`UseJava` module's :command:`add_jar` command now accepts a new
+  option `INCLUDE_MODULES` that adds its arguments to the `--module-path`
+  argument to the Java compiler. This allows building JAR files that use JPMS
+  modules in their build.

+ 40 - 13
Modules/UseJava.cmake

@@ -53,6 +53,7 @@ Creating And Installing JARs
             [SOURCES] <source1> [<source2>...] [<resource1>...]
             [RESOURCES NAMESPACE <ns1> <resource1>... [NAMESPACE <nsX> <resourceX>...]... ]
             [INCLUDE_JARS <jar1> [<jar2>...]]
+            [INCLUDE_MODULES <jar1> [<jar2>...]]
             [ENTRY_POINT <entry>]
             [VERSION <version>]
             [MANIFEST <manifest>]
@@ -109,6 +110,13 @@ Creating And Installing JARs
     jar files listed as sources are ignored (as they have been since the first
     version of this module).
 
+  ``INCLUDE_MODULES``
+    .. versionadded:: 4.3
+
+    The list of jars are added to the module path when building the java sources
+    and also to the dependencies of the target. ``INCLUDE_MODULES`` also
+    accepts other target names created by ``add_jar()``.
+
   ``ENTRY_POINT``
     Defines an entry point in the jar file.
 
@@ -703,7 +711,7 @@ function(add_jar _TARGET_NAME)
 
     set(options)  # currently there are no zero value args (aka: options)
     set(oneValueArgs "ENTRY_POINT;MANIFEST;OUTPUT_DIR;;OUTPUT_NAME;VERSION" )
-    set(multiValueArgs "GENERATE_NATIVE_HEADERS;INCLUDE_JARS;RESOURCES;SOURCES" )
+    set(multiValueArgs "GENERATE_NATIVE_HEADERS;INCLUDE_JARS;INCLUDE_MODULES;RESOURCES;SOURCES" )
 
     cmake_parse_arguments(PARSE_ARGV 1 _add_jar
                     "${options}"
@@ -837,6 +845,7 @@ function(add_jar _TARGET_NAME)
     set(_JAVA_COMPILE_FILELISTS)
     set(_JAVA_DEPENDS)
     set(_JAVA_COMPILE_DEPENDS)
+    set(_JAVA_COMPILE_MODDEPENDS)
     set(_JAVA_RESOURCE_FILES)
     set(_JAVA_RESOURCE_FILES_RELATIVE)
     foreach(_JAVA_SOURCE_FILE IN LISTS _JAVA_SOURCE_FILES)
@@ -897,6 +906,16 @@ function(add_jar _TARGET_NAME)
     foreach (resolved_cp_item IN LISTS _JAVA_COMPILE_DEPENDS)
         string(APPEND CMAKE_JAVA_INCLUDE_PATH_FINAL "${_UseJava_PATH_SEP}${resolved_cp_item}")
     endforeach ()
+    # Build dependency lists and arguments for JARs in the modulepath
+    set(javac_mp_args)
+    if (_add_jar_INCLUDE_MODULES)
+        if (Java_VERSION VERSION_LESS 9)
+            message(SEND_ERROR "INCLUDE_MODULES requires Java 9+")
+        endif()
+        __java_build_deplists(_JAVA_DEPENDS _JAVA_COMPILE_MODDEPENDS _add_jar_INCLUDE_MODULES)
+        list(JOIN _JAVA_COMPILE_MODDEPENDS "${_UseJava_PATH_SEP}" javac_mp_args)
+        set(javac_mp_args "--module-path [[${javac_mp_args}]]")
+    endif()
 
     if (_JAVA_COMPILE_FILES OR _JAVA_COMPILE_FILELISTS)
         set (_JAVA_SOURCES_FILELISTS)
@@ -921,33 +940,41 @@ function(add_jar _TARGET_NAME)
 
         cmake_language(GET_MESSAGE_LOG_LEVEL _LOG_LEVEL)
         # Compile the java files and create a list of class files
-        add_custom_command(
-            # NOTE: this command generates an artificial dependency file
-            OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
+        # NOTE: this command generates an artificial dependency file
+        set(stamp_file "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}")
+        add_custom_command(OUTPUT "${stamp_file}"
             COMMAND ${CMAKE_COMMAND}
                 -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
                 -DCMAKE_JAR_CLASSES_PREFIX=${CMAKE_JAR_CLASSES_PREFIX}
                 -P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/UseJava/ClearClassFiles.cmake
                 --log-level ${_LOG_LEVEL}
-            COMMAND ${Java_JAVAC_EXECUTABLE}
-                ${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} ${_JAVA_SOURCES_FILE}
+            DEPENDS ${_JAVA_COMPILE_FILES} ${_JAVA_COMPILE_FILELISTS} ${_JAVA_COMPILE_DEPENDS} ${_JAVA_COMPILE_MODDEPENDS} ${_JAVA_SOURCES_FILE}
             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
             COMMENT "Building Java objects for ${_TARGET_NAME}.jar"
             VERBATIM
         )
+        cmake_language(EVAL CODE "
+            add_custom_command(OUTPUT [[${stamp_file}]]
+                APPEND COMMAND [[${Java_JAVAC_EXECUTABLE}]]
+                    \${CMAKE_JAVA_COMPILE_FLAGS}
+                    -classpath [[${CMAKE_JAVA_INCLUDE_PATH_FINAL}]]
+                    ${javac_mp_args}
+                    -d [[${CMAKE_JAVA_CLASS_OUTPUT_PATH}]]
+                    \${_GENERATE_NATIVE_HEADERS}
+                    \${_JAVA_SOURCES_FILELISTS}
+            )
+        ")
+        add_custom_command(OUTPUT "${stamp_file}"
+            APPEND COMMAND ${CMAKE_COMMAND} -E touch "${stamp_file}"
+        )
+
         add_custom_command(
             OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
             COMMAND ${CMAKE_COMMAND}
                 -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
                 -DCMAKE_JAR_CLASSES_PREFIX=${CMAKE_JAR_CLASSES_PREFIX}
                 -P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/UseJava/ClassFilelist.cmake
-            DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
+            DEPENDS "${stamp_file}"
             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
             VERBATIM
         )

+ 5 - 0
Tests/CMakeLists.txt

@@ -3283,6 +3283,11 @@ if(BUILD_TESTING)
     set(JavaExportImport_BUILD_OPTIONS -DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM})
     ADD_TEST_MACRO(JavaExportImport JavaExportImport)
 
+    if("${Java_VERSION}" VERSION_GREATER_EQUAL 9)
+      set(JavaModExportImport_BUILD_OPTIONS -DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM})
+      ADD_TEST_MACRO(JavaModExportImport JavaModExportImport)
+    endif()
+
     get_filename_component(JAVACPATH ${Java_JAVAC_EXECUTABLE} REALPATH)
     get_filename_component(JNIPATH ${JAVACPATH} PATH)
     find_file(JNI_H jni.h

+ 13 - 0
Tests/JavaModExportImport/BuildExport/CMakeLists.txt

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

+ 13 - 0
Tests/JavaModExportImport/BuildExport/Foo.java

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

+ 3 - 0
Tests/JavaModExportImport/BuildExport/module-info.java

@@ -0,0 +1,3 @@
+module mod_foo {
+    exports org.foo;
+}

+ 105 - 0
Tests/JavaModExportImport/CMakeLists.txt

@@ -0,0 +1,105 @@
+cmake_minimum_required(VERSION 3.10)
+project(JavaModExportImport)
+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 ${JavaModExportImport_BINARY_DIR}/CleanupProject
+  COMMAND ${CMAKE_COMMAND} -E rm -rf ${JavaModExportImport_BINARY_DIR}/Root
+  )
+add_custom_target(CleanupTarget ALL DEPENDS ${JavaModExportImport_BINARY_DIR}/CleanupProject)
+set_property(
+  SOURCE ${JavaModExportImport_BINARY_DIR}/CleanupProject
+  PROPERTY SYMBOLIC 1
+  )
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+  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(${JavaModExportImport_SOURCE_DIR}/InitialCache.cmake.in
+               ${JavaModExportImport_BINARY_DIR}/InitialCache.cmake @ONLY)
+
+# Build the build exporter.
+add_custom_command(
+  OUTPUT ${JavaModExportImport_BINARY_DIR}/BuildExportProject
+  COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+    --build-and-test
+    ${JavaModExportImport_SOURCE_DIR}/BuildExport
+    ${JavaModExportImport_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${JavaModExportImport_BINARY_DIR}/InitialCache.cmake
+  VERBATIM
+  )
+add_custom_target(BuildExportTarget ALL DEPENDS ${JavaModExportImport_BINARY_DIR}/BuildExportProject)
+add_dependencies(BuildExportTarget CleanupTarget)
+set_property(
+  SOURCE ${JavaModExportImport_BINARY_DIR}/BuildExportProject
+  PROPERTY SYMBOLIC 1
+  )
+
+# Build and install the install exporter.
+add_custom_command(
+  OUTPUT ${JavaModExportImport_BINARY_DIR}/InstallExportProject
+  COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+    --build-and-test
+    ${JavaModExportImport_SOURCE_DIR}/InstallExport
+    ${JavaModExportImport_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${JavaModExportImport_BINARY_DIR}/InitialCache.cmake
+  VERBATIM
+  )
+add_custom_target(InstallExportTarget ALL DEPENDS ${JavaModExportImport_BINARY_DIR}/InstallExportProject)
+add_dependencies(InstallExportTarget CleanupTarget)
+set_property(
+  SOURCE ${JavaModExportImport_BINARY_DIR}/InstallExportProject
+  PROPERTY SYMBOLIC 1
+  )
+
+# Build and install the importer.
+add_custom_command(
+  OUTPUT ${JavaModExportImport_BINARY_DIR}/ImportProject
+  COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+    --build-and-test
+    ${JavaModExportImport_SOURCE_DIR}/Import
+    ${JavaModExportImport_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${JavaModExportImport_BINARY_DIR}/InitialCache.cmake
+      -DJavaBuildExportTest_DIR:PATH=${JavaModExportImport_BINARY_DIR}/BuildExport
+      -DJavaInstallExportTest_DIR:PATH=${JavaModExportImport_BINARY_DIR}/Root/share/cmake
+  VERBATIM
+  )
+add_custom_target(ImportTarget ALL DEPENDS ${JavaModExportImport_BINARY_DIR}/ImportProject)
+add_dependencies(ImportTarget BuildExportTarget InstallExportTarget)
+set_property(
+  SOURCE ${JavaModExportImport_BINARY_DIR}/ImportProject
+  PROPERTY SYMBOLIC 1
+  )
+
+add_executable(JavaModExportImport main.c)
+add_dependencies(JavaModExportImport ImportTarget)

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

@@ -0,0 +1,14 @@
+project(import Java)
+
+cmake_minimum_required(VERSION 3.10)
+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 module-info.java
+  INCLUDE_MODULES foo::foo bar::bar)

+ 13 - 0
Tests/JavaModExportImport/Import/Import.java

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

+ 4 - 0
Tests/JavaModExportImport/Import/module-info.java

@@ -0,0 +1,4 @@
+module client {
+    requires mod_foo;
+    requires mod_bar;
+}

+ 5 - 0
Tests/JavaModExportImport/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 "@JavaModExportImport_BINARY_DIR@/Root" CACHE STRING "Installation Prefix")

+ 13 - 0
Tests/JavaModExportImport/InstallExport/Bar.java

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

+ 15 - 0
Tests/JavaModExportImport/InstallExport/CMakeLists.txt

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

+ 3 - 0
Tests/JavaModExportImport/InstallExport/module-info.java

@@ -0,0 +1,3 @@
+module mod_bar {
+    exports com.bar;
+}

+ 4 - 0
Tests/JavaModExportImport/main.c

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