[ci skip] multi-user should be multiuser
[scons.git] / doc / user / java.xml
blobf53fcf4f8a108f96b9c5a1b43f189a6f11378337
1 <?xml version='1.0'?>
3 <!--
4 SPDX-FileCopyrightText: Copyright The SCons Foundation (https://scons.org)
5 SPDX-License-Identifier: MIT
6 SPDX-FileType: DOCUMENTATION
8 This file is processed by the bin/SConsDoc.py module.
9 -->
11 <!DOCTYPE sconsdoc [
12     <!ENTITY % scons SYSTEM "../scons.mod">
13     %scons;
15     <!ENTITY % builders-mod SYSTEM "../generated/builders.mod">
16     %builders-mod;
17     <!ENTITY % functions-mod SYSTEM "../generated/functions.mod">
18     %functions-mod;
19     <!ENTITY % tools-mod SYSTEM "../generated/tools.mod">
20     %tools-mod;
21     <!ENTITY % variables-mod SYSTEM "../generated/variables.mod">
22     %variables-mod;
25 <chapter id="chap-java"
26          xmlns="http://www.scons.org/dbxsd/v1.0"
27          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
28          xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
29 <title>Java Builds</title>
31 <para>
33   So far, we've been using examples of
34   building C and C++ programs
35   to demonstrate the features of &SCons;.
36   &SCons; also supports building Java programs,
37   but Java builds are handled slightly differently,
38   which reflects the ways in which
39   the Java compiler and tools
40   build programs differently than
41   other languages' tool chains.
43   </para>
45   <section>
46   <title>Building Java Class Files:  the &b-Java; Builder</title>
48     <para>
50     The basic activity when programming in Java,
51     of course, is to take one or more <filename>.java</filename> files
52     containing Java source code
53     and to call the Java compiler
54     to turn them into one or more
55     <filename>.class</filename> files.
56     In &SCons;, you do this
57     by giving the &b-link-Java; Builder
58     a target directory in which
59     to put the <filename>.class</filename> files,
60     and a source directory that contains
61     the <filename>.java</filename> files:
63     </para>
65     <scons_example name="java_java">
66       <file name="SConstruct" printme="1">
67 Java('classes', 'src')
68       </file>
69       <file name="src/Example1.java">
70 public class Example1
72   public static void main(String[] args)
73   {
74     System.out.println("Hello Java world!\n");
75   }
77       </file>
78       <file name="src/Example2.java">
79 public class Example2
81   public static void main(String[] args)
82   {
83     System.out.println("Hello Java world!\n");
84   }
86       </file>
87       <file name="src/Example3.java">
88 public class Example3
90   public static void main(String[] args)
91   {
92     System.out.println("Hello Java world!\n");
93   }
95       </file>
96     </scons_example>
98     <para>
100     If the <filename>src</filename> directory contains
101     three <filename>.java</filename> source files,
102     then running &SCons; might look like this:
104     </para>
106     <scons_output example="java_java" suffix="1">
107       <scons_output_command>scons -Q</scons_output_command>
108     </scons_output>
110     <para>
112     &SCons; will actually search the <filename>src</filename>
113     directory tree for all of the <filename>.java</filename> files.
114     The Java compiler will then create the
115     necessary class files in the <filename>classes</filename> subdirectory,
116     based on the class names found in the <filename>.java</filename> files.
118     </para>
120   </section>
122   <section>
123   <title>How &SCons; Handles Java Dependencies</title>
125     <para>
127     In addition to searching the source directory for
128     <filename>.java</filename> files,
129     &SCons; actually runs the <filename>.java</filename> files
130     through a stripped-down Java parser that figures out
131     what classes are defined.
132     In other words, &SCons; knows,
133     without you having to tell it,
134     what <filename>.class</filename> files
135     will be produced by the &javac; call.
136     So our one-liner example from the preceding section:
138     </para>
140     <scons_example name="java_java-classes">
141       <file name="SConstruct" printme="1">
142 Java('classes', 'src')
143       </file>
144       <file name="src/Example1.java">
145 public class Example1
147   public static void main(String[] args)
148   {
149     System.out.println("Hello Java world!\n");
150   }
152 public class AdditionalClass1
154   public static void main(String[] args)
155   {
156     System.out.println("Hello Java world!\n");
157   }
159       </file>
160       <file name="src/Example2.java">
161 public class Example2
163   class Inner2 {
164     public static void main(String[] args)
165     {
166       System.out.println("Hello Java world!\n");
167     }
168   }
170       </file>
171       <file name="src/Example3.java">
172 public class Example3
174   public static void main(String[] args)
175   {
176     System.out.println("Hello Java world!\n");
177   }
179 public class AdditionalClass3
181   public static void main(String[] args)
182   {
183     System.out.println("Hello Java world!\n");
184   }
186       </file>
187     </scons_example>
189     <para>
191     Will not only tell you reliably
192     that the <filename>.class</filename> files
193     in the <filename>classes</filename> subdirectory
194     are up-to-date:
196     </para>
198     <scons_output example="java_java-classes" suffix="1">
199       <scons_output_command>scons -Q</scons_output_command>
200       <scons_output_command>scons -Q classes</scons_output_command>
201     </scons_output>
203     <para>
205     But it will also remove all of the generated
206     <filename>.class</filename> files,
207     even for inner classes,
208     without you having to specify them manually.
209     For example, if our
210     <filename>Example1.java</filename>
211     and
212     <filename>Example3.java</filename>
213     files both define additional classes,
214     and the class defined in <filename>Example2.java</filename>
215     has an inner class,
216     running <userinput>scons -c</userinput>
217     will clean up all of those <filename>.class</filename> files
218     as well:
220     </para>
222     <scons_output example="java_java-classes" suffix="2">
223       <scons_output_command>scons -Q</scons_output_command>
224       <scons_output_command>scons -Q -c classes</scons_output_command>
225     </scons_output>
227     <para>
229     To ensure correct handling of <filename>.class</filename>
230     dependencies in all cases, you need to tell &SCons; which Java
231     version is being used.  This is needed because Java 1.5 changed
232     the <filename>.class</filename> file names for nested anonymous
233     inner classes.  Use the <varname>JAVAVERSION</varname> construction
234     variable to specify the version in use.  With Java 1.6, the
235     one-liner example can then be defined like this:
237     </para>
239     <sconstruct>
240 Java('classes', 'src', JAVAVERSION='1.6')
241     </sconstruct>
243     <para>
244     See <varname>JAVAVERSION</varname> in the man page for more information.
245     </para>
247   </section>
249   <section>
250   <title>Building Java Archive (<filename>.jar</filename>) Files:  the &b-Jar; Builder</title>
252     <para>
254     After building the class files,
255     it's common to collect them into
256     a Java archive (<filename>.jar</filename>) file,
257     which you do by calling the &b-link-Jar; Builder.
258     If you want to just collect all of the
259     class files within a subdirectory,
260     you can just specify that subdirectory
261     as the &b-Jar; source:
263     </para>
265     <scons_example name="java_jar1">
266       <file name="SConstruct" printme="1">
267 Java(target='classes', source='src')
268 Jar(target='test.jar', source='classes')
269       </file>
270       <file name="src/Example1.java">
271 public class Example1
273   public static void main(String[] args)
274   {
275     System.out.println("Hello Java world!\n");
276   }
278       </file>
279       <file name="src/Example2.java">
280 public class Example2
282   public static void main(String[] args)
283   {
284     System.out.println("Hello Java world!\n");
285   }
287       </file>
288       <file name="src/Example3.java">
289 public class Example3
291   public static void main(String[] args)
292   {
293     System.out.println("Hello Java world!\n");
294   }
296       </file>
297     </scons_example>
299     <para>
301     &SCons; will then pass that directory
302     to the &jar; command,
303     which will collect all of the underlying
304     <filename>.class</filename> files:
306     </para>
308     <scons_output example="java_jar1" suffix="1">
309       <scons_output_command>scons -Q</scons_output_command>
310     </scons_output>
312     <para>
314     If you want to keep all of the
315     <filename>.class</filename> files
316     for multiple programs in one location,
317     and only archive some of them in
318     each <filename>.jar</filename> file,
319     you can pass the &b-Jar; builder a
320     list of files as its source.
321     It's extremely simple to create multiple
322     <filename>.jar</filename> files this way,
323     using the lists of target class files created
324     by calls to the &b-link-Java; builder
325     as sources to the various &b-Jar; calls:
327     </para>
329     <scons_example name="java_jar2">
330       <file name="SConstruct" printme="1">
331 prog1_class_files = Java(target='classes', source='prog1')
332 prog2_class_files = Java(target='classes', source='prog2')
333 Jar(target='prog1.jar', source=prog1_class_files)
334 Jar(target='prog2.jar', source=prog2_class_files)
335       </file>
336       <file name="prog1/Example1.java">
337 public class Example1
339   public static void main(String[] args)
340   {
341     System.out.println("Hello Java world!\n");
342   }
344       </file>
345       <file name="prog1/Example2.java">
346 public class Example2
348   public static void main(String[] args)
349   {
350     System.out.println("Hello Java world!\n");
351   }
353       </file>
354       <file name="prog2/Example3.java">
355 public class Example3
357   public static void main(String[] args)
358   {
359     System.out.println("Hello Java world!\n");
360   }
362       </file>
363       <file name="prog2/Example4.java">
364 public class Example4
366   public static void main(String[] args)
367   {
368     System.out.println("Hello Java world!\n");
369   }
371       </file>
372     </scons_example>
374     <para>
376     This will then create
377     <filename>prog1.jar</filename>
378     and <filename>prog2.jar</filename>
379     next to the subdirectories
380     that contain their <filename>.java</filename> files:
382     </para>
384     <scons_output example="java_jar2" suffix="1">
385       <scons_output_command>scons -Q</scons_output_command>
386     </scons_output>
388   </section>
390   <section>
391   <title>Building C Header and Stub Files:  the &b-JavaH; Builder</title>
393     <para>
395     You can generate C header and source files
396     for implementing native methods,
397     by using the &b-link-JavaH; Builder.
398     There are several ways of using the &JavaH; Builder.
399     One typical invocation might look like:
401     </para>
403     <scons_example name="java_javah">
404       <file name="SConstruct" printme="1">
405 classes = Java(target='classes', source='src/pkg/sub')
406 JavaH(target='native', source=classes)
407       </file>
408       <file name="src/pkg/sub/Example1.java">
409 package pkg.sub;
410 public class Example1
412   public static void main(String[] args)
413   {
414   }
416       </file>
417       <file name="src/pkg/sub/Example2.java">
418 package pkg.sub;
419 public class Example2
421   public static void main(String[] args)
422   {
423   }
425       </file>
426       <file name="src/pkg/sub/Example3.java">
427 package pkg.sub;
428 public class Example3
430   public static void main(String[] args)
431   {
432   }
434       </file>
435     </scons_example>
437     <para>
439     The source is a list of class files generated by the
440     call to the &b-link-Java; Builder,
441     and the target is the output directory in
442     which we want the C header files placed.
443     The target
444     gets converted into the <option>-d</option>
445     when &SCons; runs &javah;:
447     </para>
449     <scons_output example="java_javah" suffix="1">
450       <scons_output_command>scons -Q</scons_output_command>
451     </scons_output>
453     <para>
455     In this case,
456     the call to &javah;
457     will generate the header files
458     <filename>native/pkg_sub_Example1.h</filename>,
459     <filename>native/pkg_sub_Example2.h</filename>
460     and
461     <filename>native/pkg_sub_Example3.h</filename>.
462     Notice that &SCons; remembered that the class
463     files were generated with a target directory of
464     <filename>classes</filename>,
465     and that it then specified that target directory
466     as the <option>-classpath</option> option
467     to the call to &javah;.
469     </para>
471     <para>
473     Although it's more convenient to use
474     the list of class files returned by
475     the &b-link-Java; Builder
476     as the source of a call to the &b-link-JavaH; Builder,
477     you <emphasis>can</emphasis>
478     specify the list of class files
479     by hand, if you prefer.
480     If you do,
481     you need to set the
482     &cv-link-JAVACLASSDIR; construction variable
483     when calling &b-JavaH;:
485     </para>
487     <scons_example name="java_JAVACLASSDIR">
488       <file name="SConstruct" printme="1">
489 Java(target='classes', source='src/pkg/sub')
490 class_file_list = [
491     'classes/pkg/sub/Example1.class',
492     'classes/pkg/sub/Example2.class',
493     'classes/pkg/sub/Example3.class',
495 JavaH(target='native', source=class_file_list, JAVACLASSDIR='classes')
496       </file>
497       <file name="src/pkg/sub/Example1.java">
498 package pkg.sub;
499 public class Example1
501   public static void main(String[] args)
502   {
503   }
505       </file>
506       <file name="src/pkg/sub/Example2.java">
507 package pkg.sub;
508 public class Example2
510   public static void main(String[] args)
511   {
512   }
514       </file>
515       <file name="src/pkg/sub/Example3.java">
516 package pkg.sub;
517 public class Example3
519   public static void main(String[] args)
520   {
521   }
523       </file>
524     </scons_example>
526     <para>
528     The &cv-JAVACLASSDIR; value then
529     gets converted into the <option>-classpath</option>
530     when &SCons; runs &javah;:
532     </para>
534     <scons_output example="java_JAVACLASSDIR" suffix="1">
535       <scons_output_command>scons -Q</scons_output_command>
536     </scons_output>
538     <para>
540     Lastly, if you don't want a separate header file
541     generated for each source file,
542     you can specify an explicit File Node
543     as the target of the &b-JavaH; Builder:
545     </para>
547     <scons_example name="java_javah_file">
548       <file name="SConstruct" printme="1">
549 classes = Java(target='classes', source='src/pkg/sub')
550 JavaH(target=File('native.h'), source=classes)
551       </file>
552       <file name="src/pkg/sub/Example1.java">
553 package pkg.sub;
554 public class Example1
556   public static void main(String[] args)
557   {
558   }
560       </file>
561       <file name="src/pkg/sub/Example2.java">
562 package pkg.sub;
563 public class Example2
565   public static void main(String[] args)
566   {
567   }
569       </file>
570       <file name="src/pkg/sub/Example3.java">
571 package pkg.sub;
572 public class Example3
574   public static void main(String[] args)
575   {
576   }
578       </file>
579     </scons_example>
581     <para>
583     Because &SCons; assumes by default
584     that the target of the &b-link-JavaH; builder is a directory,
585     you need to use the &File; function
586     to make sure that &SCons; doesn't
587     create a directory named <filename>native.h</filename>.
588     When a file is used, though,
589     &SCons; correctly converts the file name
590     into the &javah; <option>-o</option> option:
592     </para>
594     <scons_output example="java_javah_file" suffix="1">
595       <scons_output_command>scons -Q</scons_output_command>
596     </scons_output>
598     <para>
600     Note that the <command>javah</command> command was
601     removed from the JDK as of JDK 10, and the approved method
602     (available since JDK 8) is to use <command>javac</command>
603     to generate native headers at the same time as the Java source
604     code is compiled.  As such the &b-link-JavaH; builder
605     is of limited utility in later Java versions.
607     </para>
609   </section>
611   <section>
612   <title>Building RMI Stub and Skeleton Class Files:  the &b-RMIC; Builder</title>
614     <para>
616     You can generate Remote Method Invocation stubs
617     by using the &b-link-RMIC; Builder.
618     The source is a list of directories,
619     typically returned by a call to the &b-link-Java; Builder,
620     and the target is an output directory
621     where the <filename>_Stub.class</filename>
622     and <filename>_Skel.class</filename> files will
623     be placed:
625     </para>
627     <scons_example name="java_RMIC">
628       <file name="SConstruct" printme="1">
629 classes = Java(target='classes', source='src/pkg/sub')
630 RMIC(target='outdir', source=classes)
631       </file>
632       <file name="src/pkg/sub/Example1.java">
633 package pkg.sub;
634 public class Example1
636   public static void main(String[] args)
637   {
638   }
640       </file>
641       <file name="src/pkg/sub/Example2.java">
642 package pkg.sub;
643 public class Example2
645   public static void main(String[] args)
646   {
647   }
649       </file>
650     </scons_example>
652     <para>
654     As it did with the &b-link-JavaH; Builder,
655     &SCons; remembers the class directory
656     and passes it as the <option>-classpath</option> option
657     to &rmic;:
659     </para>
661     <scons_output example="java_RMIC" suffix="1">
662       <scons_output_command>scons -Q</scons_output_command>
663     </scons_output>
665     <para>
667     This example would generate the files
668     <filename>outdir/pkg/sub/Example1_Skel.class</filename>,
669     <filename>outdir/pkg/sub/Example1_Stub.class</filename>,
670     <filename>outdir/pkg/sub/Example2_Skel.class</filename> and
671     <filename>outdir/pkg/sub/Example2_Stub.class</filename>.
673     </para>
675   </section>
677 </chapter>