Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1# Java {#sec-language-java} 2 3Ant-based Java packages are typically built from source as follows: 4 5```nix 6stdenv.mkDerivation { 7 pname = "..."; 8 version = "..."; 9 10 src = fetchurl { /* ... */ }; 11 12 nativeBuildInputs = [ 13 ant 14 jdk 15 stripJavaArchivesHook # removes timestamp metadata from jar files 16 ]; 17 18 buildPhase = '' 19 runHook preBuild 20 ant # build the project using ant 21 runHook postBuild 22 ''; 23 24 installPhase = '' 25 runHook preInstall 26 27 # copy generated jar file(s) to an appropriate location in $out 28 install -Dm644 build/foo.jar $out/share/java/foo.jar 29 30 runHook postInstall 31 ''; 32} 33``` 34 35Note that `jdk` is an alias for the OpenJDK (self-built where available, 36or pre-built via Zulu). 37 38Also note that not using `stripJavaArchivesHook` will likely cause the 39generated `.jar` files to be non-deterministic, which is not optimal. 40Using it, however, does not always guarantee reproducibility. 41 42JAR files that are intended to be used by other packages should be 43installed in `$out/share/java`. JDKs have a stdenv setup hook that add 44any JARs in the `share/java` directories of the build inputs to the 45`CLASSPATH` environment variable. For instance, if the package `libfoo` 46installs a JAR named `foo.jar` in its `share/java` directory, and 47another package declares the attribute 48 49```nix 50{ 51 buildInputs = [ libfoo ]; 52 nativeBuildInputs = [ jdk ]; 53} 54``` 55 56then `CLASSPATH` will be set to 57`/nix/store/...-libfoo/share/java/foo.jar`. 58 59Private JARs should be installed in a location like 60`$out/share/package-name`. 61 62If your Java package provides a program, you need to generate a wrapper 63script to run it using a JRE. You can use `makeWrapper` for this: 64 65```nix 66{ 67 nativeBuildInputs = [ makeWrapper ]; 68 69 installPhase = '' 70 mkdir -p $out/bin 71 makeWrapper ${jre}/bin/java $out/bin/foo \ 72 --add-flags "-cp $out/share/java/foo.jar org.foo.Main" 73 ''; 74} 75``` 76 77Since the introduction of the Java Platform Module System in Java 9, 78Java distributions typically no longer ship with a general-purpose JRE: 79instead, they allow generating a JRE with only the modules required for 80your application(s). Because we can't predict what modules will be 81needed on a general-purpose system, the default jre package is the full 82JDK. When building a minimal system/image, you can override the 83`modules` parameter on `jre_minimal` to build a JRE with only the 84modules relevant for you: 85 86```nix 87let 88 my_jre = pkgs.jre_minimal.override { 89 modules = [ 90 # The modules used by 'something' and 'other' combined: 91 "java.base" 92 "java.logging" 93 ]; 94 }; 95 something = (pkgs.something.override { jre = my_jre; }); 96 other = (pkgs.other.override { jre = my_jre; }); 97in 98 <...> 99``` 100 101You can also specify what JDK your JRE should be based on, for example 102selecting a 'headless' build to avoid including a link to GTK+: 103 104```nix 105{ 106 my_jre = pkgs.jre_minimal.override { 107 jdk = jdk11_headless; 108 }; 109} 110``` 111 112Note all JDKs passthru `home`, so if your application requires 113environment variables like `JAVA_HOME` being set, that can be done in a 114generic fashion with the `--set` argument of `makeWrapper`: 115 116```bash 117--set JAVA_HOME ${jdk.home} 118``` 119 120It is possible to use a different Java compiler than `javac` from the 121OpenJDK. For instance, to use the GNU Java Compiler: 122 123```nix 124{ 125 nativeBuildInputs = [ gcj ant ]; 126} 127``` 128 129Here, Ant will automatically use `gij` (the GNU Java Runtime) instead of 130the OpenJRE.