--- /tmp/abo.draft 2010-11-02 20:25:42.231180030 +0100
+++ /tmp/new.draft 2010-11-02 20:25:54.655851316 +0100
@@ -1,12 +1,7 @@
-(This is a draft update to [[Packaging:Java]].)
-
These guidelines are laid out in order of relevance to packaging.
== Introduction ==
-=== Background ===
-Traditionally, Java implementations have been available under a non-free license. Free software clean room implementations of the class library largely centred around GNU Classpath. GCJ, a Java frontend for GCC, allowed for native compilation of Java software. In 2007, Sun released its reference implementation of Java under the GPL+Classpath exception as OpenJDK. This included the bytecode interpreter, just-in-time (JIT) compiler (Hotspot), and the majority of its class library. Due to the remaining small proprietary encumbrances, a project known as IcedTea was formed to build OpenJDK with entirely free tools, and provides Free software plugs for the encumbered pieces of the class libraries. Since 2008 this has enabled Fedora to ship a package under the OpenJDK name.
-
=== The Basics ===
The term Java means many things to many people: a class library, a bytecode interpreter, a JIT compiler, a language specification, etc. For the vast majority of users and developers, Java is a programming language and runtime environment that is architecture- and OS-agnostic. The normal flow of code is .java
(source file) .class
(Java bytecode) .jar
(a zip archive). In the majority of cases, a user executes a Java program by specifying a class name containing a main method (just like C and C++). Often, this is done by invoking the java
binary with a list of JAR files specifying the classpath like so:
@@ -15,13 +10,16 @@
== Java Packaging ==
The [http://www.jpackage.org JPackage Project] has defined standard file system locations and conventions for use in Java packages. Many distributions have inherited these conventions and in the vast majority of cases, Fedora follows them verbatim. We include relevant sections of the JPackage guidelines here but caution that the canonical document will always reside upstream: [http://www.jpackage.org/cgi-bin/viewvc.cgi/src/jpackage-utils/doc/jpackage-1.5-policy.xhtml?revision=HEAD&root=jpackage JPackage Guidelines] . Over time, we would like to remove any divergences in these documents, but where they are different, these Fedora guidelines will take precedence for Fedora packages.
+TODO: Find the proper jpackage link and fix it.
+
=== Package naming ===
+
Packages '''MUST''' follow the standard Fedora [[Packaging/NamingGuidelines]].
Java API documentation '''MUST''' be placed into a sub-package called %{name}-javadoc
.
==== Release tags ====
-Java packages '''MUST''' follow the standard Fedora [[Packaging:NamingGuidelines#Package_Release | Release Guidelines]]. If a package is coming into Fedora from JPackage, please refer to [[Packaging/JPackagePolicy]].
+Packages '''MUST''' follow the standard Fedora [[Packaging/NamingGuidelines#Package_Version | Package versioning guidelines]] .
=== JAR file installation ===
@@ -29,40 +27,35 @@
==== Split JAR files ====
-If a project offers the choice of packaging it as a single monolithic jar or several ones, the split packaging should be preferred.
+If a project offers the choice of packaging it as a single monolithic jar or several ones, the split packaging '''should''' be preferred.
==== Filenames ====
-If the package provides a '''single''' JAR and the filename provided by the build is %{name}.jar
then this filename '''MUST''' be used.
-
-If the package provides a '''single''' JAR and the filename provided by the build is %{name}-%{version}.jar
then this name '''MUST''' be used and a symbolic link %{name}.jar
pointing to this file '''MUST''' be installed.
-
-If the package provides a '''single''' JAR and the filename provided by the build is neither %{name}-%{version}.jar
nor %{name}.jar
then this file '''MUST''' be installed as %{name}.jar
and a symbolic link with the usual name must be provided.
-
-If the package provides more than '''one''' JAR file, the filenames assigned by the build must be used.
-
-If the project usually provides alternative JAR file names by installing symbolic links then such symlinks may be installed in the same directory as the JAR files.
+* If the package provides a '''single''' JAR and the filename provided by the build is %{name}.jar
or %{name}-%{version}.jar
then filename %{name}.jar
'''MUST''' be used.
+* If the package provides a '''single''' JAR and the filename provided by the build is neither %{name}-%{version}.jar
nor %{name}.jar
then this file '''MUST''' be installed as %{name}.jar
and a symbolic link with the usual name must be provided.
+* If the package provides more than '''one''' JAR file, the filenames assigned by the build '''MUST''' be used (without versions).
+* If the project usually provides alternative JAR file names by installing symbolic links then such symlinks '''MAY''' be installed in the same directory as the JAR files.
==== Installation directory ====
-All JAR files '''MUST''' go into %{_javadir}
or a Java-version specific directory %{_javadir}-*
as appropriate[http://lists.fedoraproject.org/pipermail/packaging/2010-January/006792.html].
+* All JAR files '''MUST''' go into %{_javadir}
or a Java-version specific directory %{_javadir}-*
as appropriate[http://lists.fedoraproject.org/pipermail/packaging/2010-January/006792.html].
-If the number of provided JAR files exceeds '''two''', you must place them into a sub-directory named %{name}
.
+* If the number of provided JAR files exceeds '''two''', you '''MUST''' place them into a sub-directory named %{name}
.
=== Javadoc installation ===
-Java API documentation uses a system known as javadoc. All javadocs '''MUST''' be installed into a subdirectory of %{_javadocdir}
. The name of the subdirectory '''MUST''' be either %{name}
or %{name}-%{version}
with a symlink %{name}
pointing to it.
-
-The javadoc subpackage '''MAY''' be declared noarch
.
+* Java API documentation uses a system known as javadoc. All javadocs '''MUST''' be created and installed into a directory of %{_javadocdir}/%{name}
.
+* Directory or symlink %{_javadocdir}/%{name}-%{version}
'''SHOULD NOT''' exist.
+* The javadoc subpackage '''MUST''' be declared noarch
even if main package is architecture specific.
=== BuildRequires and Requires ===
At a minimum, Java packages '''MUST''':
BuildRequires: java-devel [>= specific_version] -BuildRequires: jpackage-utils +BuildRequires: jpackage-utils -Requires: java >= specific_version -Requires: jpackage-utils+Requires: java >= specific_version +Requires: jpackage-utils For historical reasons, when specifying versions 1.6.0 or greater, an epoch of 1 must be included. Example: @@ -72,8 +65,9 @@ === build-classpath ===
build-classpath
is a script that can be used to generate classpaths from generic names of JAR files. Example:
-export CLASSPATH=$(build-classpath commons-logging commons-net) ++{{admon/note|Note:|Multimodule Maven projects should use javadoc:aggregate instead of javadoc:javadoc.}} + +{{admon/important|Important|Please read [[Java/JPPMavenReadme]] for details about mvn-jpp and %add_to_maven_depmap usage. }} + === Wrapper Scripts === -Applications wishing to provide a convenient method of execution '''SHOULD''' provide a wrapper script inexport CLASSPATH=$(build-classpath commons-logging commons-net xbean/xbean-reflect)+{{admon/note|Additional information|You can use either package names (all jar files will be included) or jar filenames with path prefix to select only some jar files from whole package.}} === build-jar-repository ===build-jar-repository
is similar tobuild-classpath
but instead of producing a classpath entry, it creates symlinks in a given directory. Example: @@ -115,9 +109,11 @@ %install rm -rf $RPM_BUILD_ROOT install -d -m 755 $RPM_BUILD_ROOT%{_javadir} -install -d -m 755 $RPM_BUILD_ROOT%{_datadir}/maven2/poms -install -pm 644 pom.xml $RPM_BUILD_ROOT/%{_datadir}/maven2/poms/JPP-maven-archiver.pom -%add_to_maven_depmap org.apache.maven maven-archiver %{version} JPP maven-archiver +install -d -m 755 $RPM_BUILD_ROOT%{_mavenpomdir} +install -pm 644 pom.xml $RPM_BUILD_ROOT/%{_mavenpomdir}/JPP-package-name.pom +# artifactId and jarName are usually %{name} for single module projects +%add_to_maven_depmap [groupId] [artifactId] %{version} JPP[/optional_subDir] [jarName] + ... %post %update_maven_depmap @@ -127,75 +123,119 @@ ...
%{_bindir}
. These can be as simple as this example:
+Applications wishing to provide a convenient method of execution '''SHOULD''' provide a wrapper script in %{_bindir
}. These can be as simple as this example:
-#!/bin/bash -. /usr/share/java-utils/java-functions +-[[Category:Packaging guidelines]] [[Category:Java]] +[[Category:Packaging guidelines drafts]]#!/bin/sh +if [ -f /usr/share/java-utils/java-functions ] ; +then + . /usr/share/java-utils/java-functions +else + echo "Can't find functions library, aborting" + exit 1 +fi +# Configuration MAIN_CLASS=MyCoolApp +# Set parameters set_classpath "mycoolapp" +# Let's start run "$@"+Specify your script as additional source + ++... +Source1: %{name}.jtidy.script +... ++ +and install it into %{_bindir} + ++%install +... +# shell script +mkdir -p %{buildroot}%{_bindir} +cp -ap %{SOURCE1} %{buildroot}%{_bindir}/%{name} +... ++ +Don't forget set file permissions correctly: + ++%files +... +%attr(755, root, root) %{_bindir}/* +... ++ === GCJ === +Building GCJ AOT bits is discouraged unless you have a very strong reason to include them in the packages. +Even when AOT bits are built and included in packages it is recommended to not require java-1.5.0-gcj because this will force every single user to install it even if one wants to use another JVM. + Please refer to [[Packaging/GCJGuidelines]] for GCJ-specific guidelines. === -devel packages ===-devel
packages don't really make sense for Java packages. Header files do not exist for Java packages. -== Specfile Templates == + +=== Maven pom.xml files and depmaps === +If upstream project is shipping Maven pom.xml files, these '''MUST''' be installed with the corresponding %add_to_maven_depmaps calls. + +If upstream project does not ship pom.xml file [[http://repo1.maven.org/maven2/ official maven repo]] should be checked and if there are pom.xml files they '''SHOULD''' be installed. + +{{admon/tip|Tip|[[http://mvnrepository.com/ Mvnrepository site]] can be used to ease}} + +== Specfile Template == === ant ===-Name: # see normal package guidelines -Version: # see normal package guidelines -Release: 1%{?dist} -Summary: # see normal package guidelines -Group: # see normal package guidelines -License: # see normal package guidelines -URL: # see normal package guidelines -Source0: # see normal package guidelines -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +Name: # see normal package guidelines +Version: # see normal package guidelines +Release: 1%{?dist} +Summary: # see normal package guidelines -BuildRequires: java-devel # Optionally: >= 1:1.6.0 -Requires: java >= 1:1.6.0 +Group: # see normal package guidelines +License: # see normal package guidelines +URL: # see normal package guidelines +Source0: # see normal package guidelines +BuildArch: noarch -BuildRequires: jpackage-utils -Requires: jpackage-utils +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) -BuildRequires: ant +BuildRequires: jpackage-utils +BuildRequires: java-devel + +BuildRequires: ant + +Requires: jpackage-utils + +Requires: java %description %package javadoc -Summary: Javadocs for %{name} -Group: Documentation -Requires: jpackage-utils -BuildArch: noarch +Summary: Javadocs for %{name} +Group: Documentation +Requires: jpackage-utils %description javadoc This package contains the API documentation for %{name}. -%package manual -Summary: Manual for %{name} -Group: Documentation -Requires: jpackage-utils - -%description manual -The manual for %{name}. - %prep %setup -q - find -name '*.class' -exec rm -f '{}' \; find -name '*.jar' -exec rm -f '{}' \; - - %build ant @@ -203,16 +243,10 @@ rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT%{_javadir} -cp -p [build path to jar] \ -$RPM_BUILD_ROOT%{_javadir}/%{name}-%{version}.jar -ln -s %{name}-%{version}.jar \ -$RPM_BUILD_ROOT%{_javadir}/%{name}.jar - - +cp -p [build path to jar] $RPM_BUILD_ROOT%{_javadir}/%{name}.jar mkdir -p $RPM_BUILD_ROOT%{_javadocdir}/%{name} -cp -rp [javadoc directory] \ -$RPM_BUILD_ROOT%{_javadocdir}/%{name} +cp -rp [javadoc directory] $RPM_BUILD_ROOT%{_javadocdir}/%{name} %clean rm -rf $RPM_BUILD_ROOT @@ -226,98 +260,81 @@ %defattr(-,root,root,-) %{_javadocdir}/%{name} -%files manual -%defattr(-,root,root,-) -%doc [manual directory]/* %changelog=== maven ===-Name: # see normal package guidelines -Version: # see normal package guidelines -Release: 1%{?dist} -Summary: # see normal package guidelines -Group: # see normal package guidelines -License: # see normal package guidelines -URL: # see normal package guidelines -Source0: # see normal package guidelines -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: java-devel # Optionally: >= 1:1.6.0 -Requires: java >= 1:1.6.0 - -BuildRequires: jpackage-utils -Requires: jpackage-utils - -Requires(post): jpackage-utils -Requires(postun): jpackage-utils - -BuildRequires: maven2 - -BuildRequires: maven2-plugin-compiler -BuildRequires: maven2-plugin-install -BuildRequires: maven2-plugin-jar -BuildRequires: maven2-plugin-javadoc -BuildRequires: maven2-plugin-release -BuildRequires: maven2-plugin-resources -BuildRequires: maven2-plugin-surefire +Name: # see normal package guidelines +Version: # see normal package guidelines +Release: 1%{?dist} +Summary: # see normal package guidelines + +Group: # see normal package guidelines +License: # see normal package guidelines +URL: # see normal package guidelines +Source0: # see normal package guidelines + +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildArch: noarch + +BuildRequires: jpackage-utils + +BuildRequires: java-devel + +BuildRequires: maven2 + +BuildRequires: maven-compiler-plugin +BuildRequires: maven-install-plugin +BuildRequires: maven-jar-plugin +BuildRequires: maven-javadoc-plugin +BuildRequires: maven-release-plugin +BuildRequires: maven-resources-plugin +BuildRequires: maven-surefire-plugin + +Requires: jpackage-utils + +Requires(post): jpackage-utils +Requires(postun): jpackage-utils + +Requires: java %description %package javadoc -Summary: Javadocs for %{name} -Group: Documentation -Requires: jpackage-utils -BuildArch: noarch +Summary: Javadocs for %{name} +Group: Documentation +Requires: jpackage-utils %description javadoc This package contains the API documentation for %{name}. -%package manual -Summary: Manual for %{name} -Group: Documentation -Requires: jpackage-utils - -%description manual -The manual for %{name}. - %prep %setup -q -find -name '*.class' -exec rm -f '{}' \; -find -name '*.jar' -exec rm -f '{}' \; - %build export MAVEN_REPO_LOCAL=$(pwd)/.m2/repository mkdir -p $MAVEN_REPO_LOCAL -mvn-jpp \ --Dmaven.repo.local=$MAVEN_REPO_LOCAL \ -install javadoc:javadoc +mvn-jpp -Dmaven.repo.local=$MAVEN_REPO_LOCAL \ + install javadoc:javadoc # or javadoc:aggregate %install rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT%{_javadir} -cp -p [build path to jar] \ -$RPM_BUILD_ROOT%{_javadir}/%{name}-%{version}.jar -ln -s %{name}-%{version}.jar \ -$RPM_BUILD_ROOT%{_javadir}/%{name}.jar - +cp -p [build path to jar] $RPM_BUILD_ROOT%{_javadir}/%{name}.jar mkdir -p $RPM_BUILD_ROOT%{_javadocdir}/%{name} -cp -rp [javadoc directory] \ -$RPM_BUILD_ROOT%{_javadocdir}/%{name} +cp -rp [javadoc directory] $RPM_BUILD_ROOT%{_javadocdir}/%{name} -install -d -m 755 $RPM_BUILD_ROOT%{_datadir}/maven2/poms +install -d -m 755 $RPM_BUILD_ROOT%{_mavenpomdir} install -pm 644 [path to pom] \ -$RPM_BUILD_ROOT%{_datadir}/maven2/poms/JPP-%{name}.pom + $RPM_BUILD_ROOT%{_mavenpomdir}/JPP-%{name}.pom -# artifactId and jarName are usually %{name} -%add_to_maven_depmap [groupId] [artifactId] %{version} JPP[/optional_subDir] [jarName] +%add_to_maven_depmap project_group_id project_artifact_id %{version} JPP %{name} %clean rm -rf $RPM_BUILD_ROOT @@ -331,7 +348,7 @@ %files %defattr(-,root,root,-) %{_mavenpomdir}/* -%{_mavendepmapfragdir} +%{_mavendepmapfragdir}/* %{_javadir}/* %doc @@ -339,15 +356,13 @@ %defattr(-,root,root,-) %{_javadocdir}/%{name} -%files manual -%defattr(-,root,root,-) -%doc [manual directory]/* - %changelog-For detailed instructions on the JPackage/Fedora maven, see [[Java/JPPMavenReadme]]. +{{admon/important|Depmap information|Last two arguments to %add_to_maven_depmap macro represent location of installed jar file. Using ".. jpp/foo bar" as last two arguments will mean that groupId/artifactId of package will resolve to jar file %{_javadir}/foo/bar.jar.}} + +For detailed instructions on the JPackage/Fedora maven, see the JPackage Maven rpm readme located [http://fedoraproject.org/wiki/Java/JPPMavenReadme here] . {{Anchor|JNI}} @@ -355,36 +370,39 @@ === Applicability === -Java programs that wish to make calls into native libraries do so via the Java Native Interface (JNI) by calling the Java methodSystem.loadLibrary
orSystem.load
to load a.so
file into the Java runtime environment. If a Java package contains a .so file then it is most likely either a JNI .so file (in which case the JNI guidelines apply) or a GCJ .so file (see #GCJ section above). +Java programs that wish to make calls into native libraries do so via the Java Native Interface (JNI). A Java package uses JNI if it contains a .so -=== Guideline === +{{Template:Warning}} Note that GCJ packages contain.so
s in%{_libdir}/gcj/%{name
} but they are not JNI .sos. -JAR files that require JNI shared objects '''MUST''' be installed in a directory%{_libdir}/%{name}
, with the usual filenames and optionally symlinks as provided by the build. The JNI shared objects themselves '''MUST''' also be installed in%{_libdir}/%{name}
. If the JNI-using code callsSystem.loadLibrary
it must be patched to useSystem.load
, passing it the full path to the dynamic shared object. +=== Guideline === -If the package installs a wrapper script then the script will need to add%{_libdir}/%{name}/jar filename
toCLASSPATH
. Likewise, thebuild-classpath
script will not find JAR files that uses JNI, so they need to be added manually. +JAR files that require JNI shared objects '''MUST''' be installed in%{_libdir}/%{name
}. The JNI shared objects themselves must also be installed in%{_libdir}/%{name}
. If the JNI-using code callsSystem.loadLibrary
you'll have to patch it to useSystem.load
, passing it the full path to the dynamic shared object. If the package installs a wrapper script you'll need to manually add%{_libdir}/%{name}/
toCLASSPATH
. If you are depending on a JNI-using JAR file, you'll need to add it manually --build-classpath
will not find it. === Rationale === -A JNI-using JAR file that was placed in%{_javadir}
would be loaded even if the Java runtime environment's architecture didn't match the architecture of the corresponding JNI shared object, in which case theSystem.loadLibrary
call would fail. +This is less convenient, but cleaner from a packaging point-of-view, than putting the JAR file in%{_javadir
}, and putting the JNI shared object in%{_libdir
} to be loaded from the default library path. First, JNI shared objects aredlopen
'd, anddlopen
'd shared objects should not be placed directly in%{_libdir
} since they are application-private data, and not libraries meant to be linked to directly -- that is, not meant to be shared. Second, placing the JAR file in%{_javadir
} causes the build-classpath script to always load it, even when running on a runtime environment of the wrong arch, meaning that theSystem.loadLibrary
line would fail. -The shared object isdlopen
'd specifically by the corresponding Java archive and is not meant to be loaded any other way. Thus is should not be packaged among the shared libraries in%{_libdir}
. +The plan is to eventually eliminate patching of theSystem.loadLibrary
line and wrapper script by makingjpackage-utils
multilib aware. This involves the following changes: creating%{_libdir}/java
and%{_libdir}/jni
directories; giving JNI-containing packages the ability to require an architecture-specific runtime environment; adding support for specifying the required runtime architecture in a wrapper script; modifyingjpackage-utils
's runtime scripts to search%{_libdir}/java
; modifying IcedTea to look for JNI shared objects in%{_libdir}/jni
. -Thus, though less convenient, it's cleaner from a packaging point-of-view to put the JAR and shared object in an arch- and library-specific directory. +The%{_jnidir
} rpm macro defines the main JNI jar repository. Like%{_javadir
} it is declined in-ext
and-x.y.z
variants. It follows exactly the same rules as the%{_javadir
}-derived tree structure, except that it hosts JAR files that use JNI. -The plan is to eventually eliminate patching of theSystem.loadLibrary
line and wrapper script by makingjpackage-utils
multilib aware. This involves the following changes: creating%{_libdir}/java
(AKA%{_jnidir}
) and%{_libdir}/jni
directories; giving JNI-containing packages the ability to require an architecture-specific runtime environment; adding support for specifying the required runtime architecture in a wrapper script; modifyingjpackage-utils
's runtime scripts to search%{_libdir}/java
; modifying IcedTea to look for JNI shared objects in%{_libdir}/jni
. +%{_jnidir
} usually expands into/usr/lib/java
. == Things to avoid == === Pre-built JAR files / Other bundled software === -Many Java projects re-ship their dependencies in their own releases. This is unacceptable in Fedora. Any prebuilt binaries (.jar and .class files) '''MUST''' either be removed from the source tree in%prep
or a modified source archive with the offending files remove be provided, in accordance with [[Packaging:Guidelines#No_inclusion_of_pre-built_binaries_or_libraries]] and [[Packaging:SourceURL]]. There may arise rare cases that an upstream project is distributing JAR files that are actually not re-distributable by Fedora. In this situation, a modified source archive '''MUST''' be created and used as described above. - -All packages '''MUST''' be built from source and '''MUST''' enumerate their dependencies withRequires
. They '''MUST NOT''' build against or re-ship the pre-included JAR files but instead use the JAR files provided by dependencies. - -It is a good idea to have something similar to the following at the end of%prep
: +Many Java projects re-ship their dependencies in their own releases. This is unacceptable in Fedora. All packages '''MUST''' be built from source and '''MUST''' enumerate their dependencies withRequires
. They '''MUST NOT''' build against or re-ship the pre-included JAR files but instead symlink out to the JAR files provided by dependencies. There may arise rare cases that an upstream project is distributing JAR files that are actually not re-distributable +by Fedora. In this situation, the JAR files themselves should not be redistributed -- even in the source zip. A modified source zip should be created with some sort of modifier in the name (ex. -CLEAN) along with instructions for reproducing. It is a good idea to have something similar to the following at the end of%prep
(courtesy David Walluck):-if find -name '*.class' -o -name '*.jar' | grep . >&2; then - echo >&2 "Prebuilt binaries found in the sources. See https://fedoraproject.org/wiki/Packaging:Java#Pre-built_JAR_files_.2F_Other_bundled_software for instructions." - exit 1 +JAR files="" +for j in $(find -name \*.jar); do +if [ ! -L $j ] ; then +JAR files="$JAR files $j" +fi +done +if [ ! -z "$JAR files" ] ; then +echo "These JAR files should be deleted and symlinked to system JAR files: $JAR files" +exit 1 fi@@ -399,5 +417,5 @@ sed -i '/class-path/I d' META-INF/MANIFEST.MF