2020-11-28 14:14:45 +00:00
|
|
|
# Java {#sec-language-java}
|
|
|
|
|
|
|
|
Ant-based Java packages are typically built from source as follows:
|
|
|
|
|
|
|
|
```nix
|
|
|
|
stdenv.mkDerivation {
|
2024-03-17 17:52:03 +00:00
|
|
|
pname = "...";
|
|
|
|
version = "...";
|
|
|
|
|
2024-03-27 18:10:27 +00:00
|
|
|
src = fetchurl { /* ... */ };
|
2020-11-28 14:14:45 +00:00
|
|
|
|
2024-03-17 17:52:03 +00:00
|
|
|
nativeBuildInputs = [
|
|
|
|
ant
|
|
|
|
jdk
|
|
|
|
stripJavaArchivesHook # removes timestamp metadata from jar files
|
|
|
|
];
|
|
|
|
|
|
|
|
buildPhase = ''
|
|
|
|
runHook preBuild
|
|
|
|
ant # build the project using ant
|
|
|
|
runHook postBuild
|
|
|
|
'';
|
|
|
|
|
|
|
|
installPhase = ''
|
|
|
|
runHook preInstall
|
2020-11-28 14:14:45 +00:00
|
|
|
|
2024-03-17 17:52:03 +00:00
|
|
|
# copy generated jar file(s) to an appropriate location in $out
|
|
|
|
install -Dm644 build/foo.jar $out/share/java/foo.jar
|
|
|
|
|
|
|
|
runHook postInstall
|
|
|
|
'';
|
2020-11-28 14:14:45 +00:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Note that `jdk` is an alias for the OpenJDK (self-built where available,
|
2024-11-02 21:10:32 +00:00
|
|
|
or pre-built via Zulu).
|
2020-11-28 14:14:45 +00:00
|
|
|
|
2024-03-17 17:52:03 +00:00
|
|
|
Also note that not using `stripJavaArchivesHook` will likely cause the
|
|
|
|
generated `.jar` files to be non-deterministic, which is not optimal.
|
|
|
|
Using it, however, does not always guarantee reproducibility.
|
|
|
|
|
2020-11-28 14:14:45 +00:00
|
|
|
JAR files that are intended to be used by other packages should be
|
|
|
|
installed in `$out/share/java`. JDKs have a stdenv setup hook that add
|
|
|
|
any JARs in the `share/java` directories of the build inputs to the
|
|
|
|
`CLASSPATH` environment variable. For instance, if the package `libfoo`
|
|
|
|
installs a JAR named `foo.jar` in its `share/java` directory, and
|
|
|
|
another package declares the attribute
|
|
|
|
|
|
|
|
```nix
|
2024-03-27 18:10:27 +00:00
|
|
|
{
|
|
|
|
buildInputs = [ libfoo ];
|
|
|
|
nativeBuildInputs = [ jdk ];
|
|
|
|
}
|
2020-11-28 14:14:45 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
then `CLASSPATH` will be set to
|
|
|
|
`/nix/store/...-libfoo/share/java/foo.jar`.
|
|
|
|
|
|
|
|
Private JARs should be installed in a location like
|
|
|
|
`$out/share/package-name`.
|
|
|
|
|
|
|
|
If your Java package provides a program, you need to generate a wrapper
|
|
|
|
script to run it using a JRE. You can use `makeWrapper` for this:
|
|
|
|
|
|
|
|
```nix
|
2024-03-27 18:10:27 +00:00
|
|
|
{
|
|
|
|
nativeBuildInputs = [ makeWrapper ];
|
2020-11-28 14:14:45 +00:00
|
|
|
|
2024-03-27 18:10:27 +00:00
|
|
|
installPhase = ''
|
|
|
|
mkdir -p $out/bin
|
|
|
|
makeWrapper ${jre}/bin/java $out/bin/foo \
|
|
|
|
--add-flags "-cp $out/share/java/foo.jar org.foo.Main"
|
|
|
|
'';
|
|
|
|
}
|
2020-11-28 14:14:45 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
Since the introduction of the Java Platform Module System in Java 9,
|
|
|
|
Java distributions typically no longer ship with a general-purpose JRE:
|
|
|
|
instead, they allow generating a JRE with only the modules required for
|
|
|
|
your application(s). Because we can't predict what modules will be
|
|
|
|
needed on a general-purpose system, the default jre package is the full
|
|
|
|
JDK. When building a minimal system/image, you can override the
|
|
|
|
`modules` parameter on `jre_minimal` to build a JRE with only the
|
|
|
|
modules relevant for you:
|
|
|
|
|
|
|
|
```nix
|
|
|
|
let
|
|
|
|
my_jre = pkgs.jre_minimal.override {
|
|
|
|
modules = [
|
|
|
|
# The modules used by 'something' and 'other' combined:
|
|
|
|
"java.base"
|
|
|
|
"java.logging"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
something = (pkgs.something.override { jre = my_jre; });
|
|
|
|
other = (pkgs.other.override { jre = my_jre; });
|
|
|
|
in
|
2024-03-27 18:39:55 +00:00
|
|
|
<...>
|
2020-11-28 14:14:45 +00:00
|
|
|
```
|
|
|
|
|
2021-09-30 08:34:51 +00:00
|
|
|
You can also specify what JDK your JRE should be based on, for example
|
|
|
|
selecting a 'headless' build to avoid including a link to GTK+:
|
|
|
|
|
|
|
|
```nix
|
2024-03-27 18:10:27 +00:00
|
|
|
{
|
|
|
|
my_jre = pkgs.jre_minimal.override {
|
|
|
|
jdk = jdk11_headless;
|
|
|
|
};
|
|
|
|
}
|
2021-09-30 08:34:51 +00:00
|
|
|
```
|
|
|
|
|
2020-11-28 14:14:45 +00:00
|
|
|
Note all JDKs passthru `home`, so if your application requires
|
|
|
|
environment variables like `JAVA_HOME` being set, that can be done in a
|
|
|
|
generic fashion with the `--set` argument of `makeWrapper`:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
--set JAVA_HOME ${jdk.home}
|
|
|
|
```
|
|
|
|
|
|
|
|
It is possible to use a different Java compiler than `javac` from the
|
|
|
|
OpenJDK. For instance, to use the GNU Java Compiler:
|
|
|
|
|
|
|
|
```nix
|
2024-03-27 18:10:27 +00:00
|
|
|
{
|
|
|
|
nativeBuildInputs = [ gcj ant ];
|
|
|
|
}
|
2020-11-28 14:14:45 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
Here, Ant will automatically use `gij` (the GNU Java Runtime) instead of
|
|
|
|
the OpenJRE.
|