summaryrefslogtreecommitdiff
path: root/eclass
diff options
context:
space:
mode:
Diffstat (limited to 'eclass')
-rw-r--r--eclass/Manifest.gzbin40358 -> 40353 bytes
-rw-r--r--eclass/java-pkg-simple.eclass335
2 files changed, 297 insertions, 38 deletions
diff --git a/eclass/Manifest.gz b/eclass/Manifest.gz
index 33e59119f685..e41b89498643 100644
--- a/eclass/Manifest.gz
+++ b/eclass/Manifest.gz
Binary files differ
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