diff options
Diffstat (limited to 'eclass')
-rw-r--r-- | eclass/Manifest.gz | bin | 40358 -> 40353 bytes | |||
-rw-r--r-- | eclass/java-pkg-simple.eclass | 335 |
2 files changed, 297 insertions, 38 deletions
diff --git a/eclass/Manifest.gz b/eclass/Manifest.gz Binary files differindex 33e59119f685..e41b89498643 100644 --- a/eclass/Manifest.gz +++ b/eclass/Manifest.gz diff --git a/eclass/java-pkg-simple.eclass b/eclass/java-pkg-simple.eclass index ce4a62f048da..f3f67e7de408 100644 --- a/eclass/java-pkg-simple.eclass +++ b/eclass/java-pkg-simple.eclass @@ -1,4 +1,4 @@ -# Copyright 2004-2024 Gentoo Authors +# Copyright 2004-2025 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 # @ECLASS: java-pkg-simple.eclass @@ -11,7 +11,9 @@ # @DESCRIPTION: # This class is intended to build pure Java packages from Java sources # without the use of any build instructions shipped with the sources. -# There is no support for generating source files, or for controlling +# It can generate module-info.java files and supports adding the Main-Class +# and the Automatic-Module-Name attributes to MANIFEST.MF. There is no +# further support for generating source files, or for controlling # the META-INF of the resulting jar, although these issues may be # addressed by an ebuild by putting corresponding files into the target # directory before calling the src_compile function of this eclass. @@ -111,7 +113,6 @@ fi # ) # @CODE -# @DESCRIPTION: # @ECLASS_VARIABLE: JAVA_RESOURCE_DIRS # @DEFAULT_UNSET # @DESCRIPTION: @@ -225,6 +226,50 @@ fi # @DESCRIPTION: # It is almost equivalent to ${JAVA_RESOURCE_DIRS} in src_test. +# @ECLASS_VARIABLE: JAVA_INTERMEDIATE_JAR_NAME +# @DEFAULT_UNSET +# @DESCRIPTION: +# Name of the intermediate jar file excluding the '.jar' suffix and also name of the +# ejavac output directory which are needed by 'jdeps --generate-module-info'. +# @CODE +# Examples: +# JAVA_INTERMEDIATE_JAR_NAME="org.apache.${PN/-/.}" +# JAVA_INTERMEDIATE_JAR_NAME="com.github.marschall.memoryfilesystem" +# @CODE + +# @ECLASS_VARIABLE: JAVA_MODULE_INFO_OUT +# @DEFAULT_UNSET +# @DESCRIPTION: +# Used by java-pkg-simple_generate-module-info. +# It is the directory where module-info.java will be created. +# Only when this variable is set, module-info.java will be created. +# @CODE +# Example: +# JAVA_MODULE_INFO_OUT="src/main" +# @CODE + +# @ECLASS_VARIABLE: JAVA_MODULE_INFO_RELEASE +# @DESCRIPTION: +# Used by java-pkg-simple_generate-module-info. +# Correlates to JAVA_RELEASE_SRC_DIRS. +# When this variable is set, module-info.java will be placed in +# ${JAVA_MODULE_INFO_OUT}/${JAVA_INTERMEDIATE_JAR_NAME}/versions/${JAVA_MODULE_INFO_RELEASE} + +# @ECLASS_VARIABLE: JAVA_RELEASE_SRC_DIRS +# @DEFAULT_UNSET +# @DESCRIPTION: +# An associative array of directories with release-specific sources which are +# used for building multi-release jar files. +# @CODE +# Example: +# JAVA_RELEASE_SRC_DIRS=( +# ["9"]="prov/src/main/jdk1.9" +# ["11"]="prov/src/main/jdk1.11" +# ["15"]="prov/src/main/jdk1.15" +# ["21"]="prov/src/main/jdk21" +# ) +# @CODE + # @FUNCTION: java-pkg-simple_getclasspath # @USAGE: java-pkg-simple_getclasspath # @INTERNAL @@ -276,6 +321,88 @@ java-pkg-simple_getclasspath() { debug-print "CLASSPATH=${classpath}" } +# @FUNCTION: java-pkg-simple_getmodulepath +# @USAGE: java-pkg-simple_getmodulepath +# @INTERNAL +# @DESCRIPTION: +# Cloned from java-pkg-simple_getclasspath, dropped 'deep_jars' +# and replaced s/classpath/modulepath/g. +# +# It is needed for java-pkg-simple_generate-module-info where using classpath +# would cause problems with '--with-dependencies'. +# And it is also used for compilation. +# +# Note that the variable "modulepath" needs to be defined before +# calling this function. +java-pkg-simple_getmodulepath() { + debug-print-function ${FUNCNAME} $* + + local dependency + local buildonly_jars="--build-only" + + # the extra classes that are not installed by portage + modulepath+=":${JAVA_GENTOO_CLASSPATH_EXTRA}" + + # the extra classes that are installed by portage + for dependency in ${JAVA_CLASSPATH_EXTRA}; do + modulepath="${modulepath}:$(java-pkg_getjars ${buildonly_jars} \ + ${dependency})" + done + + # add test dependencies if USE FLAG 'test' is set + if has test ${JAVA_PKG_IUSE} && use test; then + for dependency in ${JAVA_TEST_GENTOO_CLASSPATH}; do + modulepath="${modulepath}:$(java-pkg_getjars ${buildonly_jars} \ + ${dependency})" + done + fi + + # add the RUNTIME dependencies + for dependency in ${JAVA_GENTOO_CLASSPATH}; do + modulepath="${modulepath}:$(java-pkg_getjars ${dependency})" + done + + # purify modulepath + while [[ $modulepath = *::* ]]; do modulepath="${modulepath//::/:}"; done + modulepath=${modulepath%:} + modulepath=${modulepath#:} + + debug-print "modulepath=${modulepath}" +} + +# @FUNCTION: java-pkg-simple_generate-module-info +# @USAGE: java-pkg-simple_generate-module-info +# @INTERNAL +# @DESCRIPTION: +# Calls jdeps --generate-module-info which generates module-info.java. +# Requires an intermediate jar file to be named as "${JAVA_INTERMEDIATE_JAR_NAME}.jar". +java-pkg-simple_generate-module-info() { + debug-print-function ${FUNCNAME} $* + + local modulepath="" jdeps_args="" + java-pkg-simple_getmodulepath + + # Default to release 9 in order to avoid having to set it in the ebuild. + : "${JAVA_MODULE_INFO_RELEASE:=9}" + + if [[ ${JAVA_MODULE_INFO_RELEASE} ]]; then + jdeps_args="${jdeps_args} --multi-release ${JAVA_MODULE_INFO_RELEASE}" + fi + + if [[ ${modulepath} ]]; then + jdeps_args="${jdeps_args} --module-path ${modulepath}" + jdeps_args="${jdeps_args} --add-modules=ALL-MODULE-PATH" + fi + debug-print "jdeps_args is ${jdeps_args}" + + jdeps \ + --generate-module-info "${JAVA_MODULE_INFO_OUT}" \ + ${jdeps_args} \ + "${JAVA_INTERMEDIATE_JAR_NAME}.jar" || die + + moduleinfo=$(find -type f -name module-info.java) +} + # @FUNCTION: java-pkg-simple_test_with_pkgdiff_ # @INTERNAL # @DESCRIPTION: @@ -374,50 +501,162 @@ java-pkg-simple_src_compile() { java-pkg_gen-cp JAVA_GENTOO_CLASSPATH fi - # gather sources - # if target < 9, we need to compile module-info.java separately - # as this feature is not supported before Java 9 - local target="$(java-pkg_get-target)" - if [[ ${target#1.} -lt 9 ]]; then - find "${JAVA_SRC_DIR[@]}" -name \*.java ! -name module-info.java > ${sources} - else - find "${JAVA_SRC_DIR[@]}" -name \*.java > ${sources} - fi - moduleinfo=$(find "${JAVA_SRC_DIR[@]}" -name module-info.java) + # generate module-info.java only if JAVA_MODULE_INFO_OUT is defined in the ebuild + if [[ ${JAVA_MODULE_INFO_OUT} && ${JAVA_INTERMEDIATE_JAR_NAME} ]]; then - # create the target directory - mkdir -p ${classes} || die "Could not create target directory" + local jdk="$(depend-java-query --get-lowest "${DEPEND}")" + if [[ "${jdk#1.}" -lt 9 ]]; then + die "Wrong DEPEND, needs at least virtual/jdk-9" + fi - # compile - local classpath="" - java-pkg-simple_getclasspath - java-pkg-simple_prepend_resources ${classes} "${JAVA_RESOURCE_DIRS[@]}" + local classpath="" + java-pkg-simple_getclasspath - if [[ -z ${moduleinfo} ]] || [[ ${target#1.} -lt 9 ]]; then + # gather sources and compile classes for the intermediate jar file + find "${JAVA_SRC_DIR[@]}" -name \*.java ! -name module-info.java > ${sources} ejavac -d ${classes} -encoding ${JAVA_ENCODING}\ ${classpath:+-classpath ${classpath}} ${JAVAC_ARGS} @${sources} - else - ejavac -d ${classes} -encoding ${JAVA_ENCODING}\ - ${classpath:+--module-path ${classpath}} --module-version ${PV}\ - ${JAVAC_ARGS} @${sources} + + java-pkg-simple_prepend_resources ${classes} "${JAVA_RESOURCE_DIRS[@]}" + + # package the intermediate jar file + # The intermediate jar file is a precondition for jdeps to generate + # a module-info.java file. + jar cvf "${JAVA_INTERMEDIATE_JAR_NAME}.jar" \ + -C target/classes . || die + + # now, generate module-info.java + java-pkg-simple_generate-module-info + debug-print "generated moduleinfo is ${moduleinfo}" + + # If JAVA_RELEASE_SRC_DIRS was not set in the ebuild, set it now: + if [[ ${JAVA_MODULE_INFO_RELEASE} && -z ${JAVA_RELEASE_SRC_DIRS[@]} ]]; then + # TODO: use JAVA_MODULE_INFO_RELEASE instead of fixed value. + JAVA_RELEASE_SRC_DIRS=( ["9"]=${JAVA_MODULE_INFO_OUT}/${JAVA_INTERMEDIATE_JAR_NAME}"/versions/9" ) + fi fi - # handle module-info.java separately as it needs at least JDK 9 - if [[ -n ${moduleinfo} ]] && [[ ${target#1.} -lt 9 ]]; then - if java-pkg_is-vm-version-ge "9" ; then - local tmp_source=${JAVA_PKG_WANT_SOURCE} tmp_target=${JAVA_PKG_WANT_TARGET} + # JEP 238 multi-release support, https://openjdk.org/jeps/238 #900433 + # + # Basic support for building multi-release jar files according to JEP 238. + # A multi-release jar file has release-specific classes in directories + # under META-INF/versions/. + # Its META-INF/MANIFEST.MF contains the line: 'Multi-Release: true'. + if [[ -n ${JAVA_RELEASE_SRC_DIRS[@]} ]]; then + # Ensure correct virtual/jdk version + # Initialize a variable to track the highest key + local highest_version=-1 + + # Loop through the keys of the associative array + for key in "${!JAVA_RELEASE_SRC_DIRS[@]}"; do + # Compare the numeric value of the key + if [[ key -gt highest_version ]]; then + highest_version="$key" + fi + done - JAVA_PKG_WANT_SOURCE="9" - JAVA_PKG_WANT_TARGET="9" + local jdk="$(depend-java-query --get-lowest "${DEPEND}")" + if [[ "${jdk#1.}" -lt "${highest_version}" ]]; then + die "Wrong DEPEND, needs at least virtual/jdk-${highest_version}" + fi + + local classpath="" + java-pkg-simple_getclasspath + + # An intermediate jar file might already exist from generation of the + # module-info.java file + if [[ ! $(find . -name ${JAVA_INTERMEDIATE_JAR_NAME}.jar) ]]; then + einfo "generating intermediate for multi-release" + # gather sources and compile classes for the intermediate jar file + find "${JAVA_SRC_DIR[@]}" -name \*.java ! -name module-info.java > ${sources} ejavac -d ${classes} -encoding ${JAVA_ENCODING}\ - ${classpath:+--module-path ${classpath}} --module-version ${PV}\ - ${JAVAC_ARGS} "${moduleinfo}" + ${classpath:+-classpath ${classpath}} ${JAVAC_ARGS} @${sources} - JAVA_PKG_WANT_SOURCE=${tmp_source} - JAVA_PKG_WANT_TARGET=${tmp_target} + java-pkg-simple_prepend_resources ${classes} "${JAVA_RESOURCE_DIRS[@]}" + + # package the intermediate jar file + # The intermediate jar file is a precondition for jdeps to generate + # a module-info.java file. + jar cvf "${JAVA_INTERMEDIATE_JAR_NAME}.jar" \ + -C target/classes . || die + fi + + local tmp_source=${JAVA_PKG_WANT_SOURCE} tmp_target=${JAVA_PKG_WANT_TARGET} + + # compile content of release-specific source directories + local version + for version in "${!JAVA_RELEASE_SRC_DIRS[@]}"; do + local release="${version}" + local reldir="${JAVA_RELEASE_SRC_DIRS[${version}]}" + debug-print "Release is ${release}, directory is ${reldir}" + + JAVA_PKG_WANT_SOURCE="${release}" + JAVA_PKG_WANT_TARGET="${release}" + + local modulepath="" + java-pkg-simple_getmodulepath + + # compile sources in ${reldir} + ejavac \ + -d target/versions/${release} \ + -encoding ${JAVA_ENCODING} \ + -classpath "${modulepath}:${JAVA_INTERMEDIATE_JAR_NAME}.jar" \ + --module-path "${modulepath}:${JAVA_INTERMEDIATE_JAR_NAME}.jar" \ + --module-version ${PV} \ + --patch-module "${JAVA_INTERMEDIATE_JAR_NAME}"="${JAVA_INTERMEDIATE_JAR_NAME}.jar" \ + ${JAVAC_ARGS} $(find ${reldir} -type f -name '*.java') + + JAVA_GENTOO_CLASSPATH_EXTRA+=":target/versions/${release}" + done + + JAVA_PKG_WANT_SOURCE=${tmp_source} + JAVA_PKG_WANT_TARGET=${tmp_target} + else + # gather sources + # if target < 9, we need to compile module-info.java separately + # as this feature is not supported before Java 9 + local target="$(java-pkg_get-target)" + if [[ ${target#1.} -lt 9 ]]; then + find "${JAVA_SRC_DIR[@]}" -name \*.java ! -name module-info.java > ${sources} else - eqawarn "Need at least JDK 9 to compile module-info.java in src_compile." - eqawarn "Please adjust DEPEND accordingly. See https://bugs.gentoo.org/796875#c3" + find "${JAVA_SRC_DIR[@]}" -name \*.java > ${sources} + fi + moduleinfo=$(find "${JAVA_SRC_DIR[@]}" -name module-info.java) + + # create the target directory + mkdir -p ${classes} || die "Could not create target directory" + + # compile + local classpath="" + java-pkg-simple_getclasspath + java-pkg-simple_prepend_resources ${classes} "${JAVA_RESOURCE_DIRS[@]}" + + if [[ -z ${moduleinfo} ]] || [[ ${target#1.} -lt 9 ]]; then + ejavac -d ${classes} -encoding ${JAVA_ENCODING}\ + ${classpath:+-classpath ${classpath}} ${JAVAC_ARGS} @${sources} + else + ejavac -d ${classes} -encoding ${JAVA_ENCODING}\ + ${classpath:+--module-path ${classpath}} --module-version ${PV}\ + ${JAVAC_ARGS} @${sources} + fi + + # handle module-info.java separately as it needs at least JDK 9 + if [[ -n ${moduleinfo} ]] && [[ ${target#1.} -lt 9 ]]; then + if java-pkg_is-vm-version-ge "9" ; then + local tmp_source=${JAVA_PKG_WANT_SOURCE} tmp_target=${JAVA_PKG_WANT_TARGET} + + JAVA_PKG_WANT_SOURCE="9" + JAVA_PKG_WANT_TARGET="9" + ejavac -d ${classes} -encoding ${JAVA_ENCODING}\ + ${classpath:+--module-path ${classpath}} --module-version ${PV}\ + ${JAVAC_ARGS} "${moduleinfo}" + + JAVA_PKG_WANT_SOURCE=${tmp_source} + JAVA_PKG_WANT_TARGET=${tmp_target} + else + eqawarn "Need at least JDK 9 to compile module-info.java in src_compile." + eqawarn "Please adjust DEPEND accordingly. See https://bugs.gentoo.org/796875#c3" + fi fi fi @@ -442,14 +681,29 @@ java-pkg-simple_src_compile() { fi # package - local jar_args + local jar_args multi_release="" + if [[ -n ${JAVA_RELEASE_SRC_DIRS[@]} ]]; then + # Preparing the multi_release variable. From multi-release compilation + # the release-specific classes are sorted in target/versions/${release} + # directories. + + # TODO: + # Could this possibly be simplified with printf? + pushd target/versions > /dev/null || die + for version in $(ls -d * | sort -g); do + debug-print "Version is ${version}" + multi_release="${multi_release} --release ${version} -C target/versions/${version} . " + done + popd > /dev/null || die + fi + if [[ -e ${classes}/META-INF/MANIFEST.MF ]]; then sed '/Created-By: /Id' -i ${classes}/META-INF/MANIFEST.MF jar_args="cfm ${JAVA_JAR_FILENAME} ${classes}/META-INF/MANIFEST.MF" else jar_args="cf ${JAVA_JAR_FILENAME}" fi - jar ${jar_args} -C ${classes} . || die "jar failed" + jar ${jar_args} -C ${classes} . ${multi_release} || die "jar failed" if [[ -n "${JAVA_AUTOMATIC_MODULE_NAME}" ]]; then echo "Automatic-Module-Name: ${JAVA_AUTOMATIC_MODULE_NAME}" \ >> "${T}/add-to-MANIFEST.MF" || die "adding module name failed" @@ -463,6 +717,11 @@ java-pkg-simple_src_compile() { || die "updating MANIFEST.MF failed" rm -f "${T}/add-to-MANIFEST.MF" || die "cannot remove" fi + + unset JAVA_INTERMEDIATE_JAR_NAME + unset JAVA_MODULE_INFO_OUT + unset JAVA_MODULE_INFO_RELEASE + unset JAVA_RELEASE_SRC_DIRS } # @FUNCTION: java-pkg-simple_src_install |