diff --git a/Help/release/dev/UseJava-include-modules.rst b/Help/release/dev/UseJava-include-modules.rst new file mode 100644 index 0000000000..a26e8ee708 --- /dev/null +++ b/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. diff --git a/Modules/UseJava.cmake b/Modules/UseJava.cmake index c7a58f4a45..4192169e0e 100644 --- a/Modules/UseJava.cmake +++ b/Modules/UseJava.cmake @@ -53,6 +53,7 @@ Creating And Installing JARs [SOURCES] [...] [...] [RESOURCES NAMESPACE ... [NAMESPACE ...]... ] [INCLUDE_JARS [...]] + [INCLUDE_MODULES [...]] [ENTRY_POINT ] [VERSION ] [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 ) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index c4bd94b678..73c29e9eb1 100644 --- a/Tests/CMakeLists.txt +++ b/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 diff --git a/Tests/JavaModExportImport/BuildExport/CMakeLists.txt b/Tests/JavaModExportImport/BuildExport/CMakeLists.txt new file mode 100644 index 0000000000..f818f444d9 --- /dev/null +++ b/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) diff --git a/Tests/JavaModExportImport/BuildExport/Foo.java b/Tests/JavaModExportImport/BuildExport/Foo.java new file mode 100644 index 0000000000..c0e2a1a892 --- /dev/null +++ b/Tests/JavaModExportImport/BuildExport/Foo.java @@ -0,0 +1,13 @@ +package org.foo; + +public class Foo +{ + public Foo() + { + } + + public void printName() + { + System.out.println("Foo"); + } +} diff --git a/Tests/JavaModExportImport/BuildExport/module-info.java b/Tests/JavaModExportImport/BuildExport/module-info.java new file mode 100644 index 0000000000..aeb0e17a4c --- /dev/null +++ b/Tests/JavaModExportImport/BuildExport/module-info.java @@ -0,0 +1,3 @@ +module mod_foo { + exports org.foo; +} diff --git a/Tests/JavaModExportImport/CMakeLists.txt b/Tests/JavaModExportImport/CMakeLists.txt new file mode 100644 index 0000000000..5326457851 --- /dev/null +++ b/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) diff --git a/Tests/JavaModExportImport/Import/CMakeLists.txt b/Tests/JavaModExportImport/Import/CMakeLists.txt new file mode 100644 index 0000000000..f8f773a92e --- /dev/null +++ b/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) diff --git a/Tests/JavaModExportImport/Import/Import.java b/Tests/JavaModExportImport/Import/Import.java new file mode 100644 index 0000000000..46b1e9a3bb --- /dev/null +++ b/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(); + } +} diff --git a/Tests/JavaModExportImport/Import/module-info.java b/Tests/JavaModExportImport/Import/module-info.java new file mode 100644 index 0000000000..9d719cd1b4 --- /dev/null +++ b/Tests/JavaModExportImport/Import/module-info.java @@ -0,0 +1,4 @@ +module client { + requires mod_foo; + requires mod_bar; +} diff --git a/Tests/JavaModExportImport/InitialCache.cmake.in b/Tests/JavaModExportImport/InitialCache.cmake.in new file mode 100644 index 0000000000..cc7871eb3c --- /dev/null +++ b/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") diff --git a/Tests/JavaModExportImport/InstallExport/Bar.java b/Tests/JavaModExportImport/InstallExport/Bar.java new file mode 100644 index 0000000000..dfa941c495 --- /dev/null +++ b/Tests/JavaModExportImport/InstallExport/Bar.java @@ -0,0 +1,13 @@ +package com.bar; + +public class Bar +{ + public Bar() + { + } + + public void printName() + { + System.out.println("Bar"); + } +} diff --git a/Tests/JavaModExportImport/InstallExport/CMakeLists.txt b/Tests/JavaModExportImport/InstallExport/CMakeLists.txt new file mode 100644 index 0000000000..5997bdc008 --- /dev/null +++ b/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) diff --git a/Tests/JavaModExportImport/InstallExport/module-info.java b/Tests/JavaModExportImport/InstallExport/module-info.java new file mode 100644 index 0000000000..7c8b62d7e5 --- /dev/null +++ b/Tests/JavaModExportImport/InstallExport/module-info.java @@ -0,0 +1,3 @@ +module mod_bar { + exports com.bar; +} diff --git a/Tests/JavaModExportImport/main.c b/Tests/JavaModExportImport/main.c new file mode 100644 index 0000000000..8488f4e58f --- /dev/null +++ b/Tests/JavaModExportImport/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +}