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.
12 <!ENTITY % scons SYSTEM "../scons.mod">
15 <!ENTITY % builders-mod SYSTEM "../generated/builders.mod">
17 <!ENTITY % functions-mod SYSTEM "../generated/functions.mod">
19 <!ENTITY % tools-mod SYSTEM "../generated/tools.mod">
21 <!ENTITY % variables-mod SYSTEM "../generated/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>
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.
46 <title>Building Java Class Files: the &b-Java; Builder</title>
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:
65 <scons_example name="java_java">
66 <file name="SConstruct" printme="1">
67 Java('classes', 'src')
69 <file name="src/Example1.java">
72 public static void main(String[] args)
74 System.out.println("Hello Java world!\n");
78 <file name="src/Example2.java">
81 public static void main(String[] args)
83 System.out.println("Hello Java world!\n");
87 <file name="src/Example3.java">
90 public static void main(String[] args)
92 System.out.println("Hello Java world!\n");
100 If the <filename>src</filename> directory contains
101 three <filename>.java</filename> source files,
102 then running &SCons; might look like this:
106 <scons_output example="java_java" suffix="1">
107 <scons_output_command>scons -Q</scons_output_command>
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.
123 <title>How &SCons; Handles Java Dependencies</title>
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:
140 <scons_example name="java_java-classes">
141 <file name="SConstruct" printme="1">
142 Java('classes', 'src')
144 <file name="src/Example1.java">
145 public class Example1
147 public static void main(String[] args)
149 System.out.println("Hello Java world!\n");
152 public class AdditionalClass1
154 public static void main(String[] args)
156 System.out.println("Hello Java world!\n");
160 <file name="src/Example2.java">
161 public class Example2
164 public static void main(String[] args)
166 System.out.println("Hello Java world!\n");
171 <file name="src/Example3.java">
172 public class Example3
174 public static void main(String[] args)
176 System.out.println("Hello Java world!\n");
179 public class AdditionalClass3
181 public static void main(String[] args)
183 System.out.println("Hello Java world!\n");
191 Will not only tell you reliably
192 that the <filename>.class</filename> files
193 in the <filename>classes</filename> subdirectory
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>
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.
210 <filename>Example1.java</filename>
212 <filename>Example3.java</filename>
213 files both define additional classes,
214 and the class defined in <filename>Example2.java</filename>
216 running <userinput>scons -c</userinput>
217 will clean up all of those <filename>.class</filename> files
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>
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:
240 Java('classes', 'src', JAVAVERSION='1.6')
244 See <varname>JAVAVERSION</varname> in the man page for more information.
250 <title>Building Java Archive (<filename>.jar</filename>) Files: the &b-Jar; Builder</title>
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:
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')
270 <file name="src/Example1.java">
271 public class Example1
273 public static void main(String[] args)
275 System.out.println("Hello Java world!\n");
279 <file name="src/Example2.java">
280 public class Example2
282 public static void main(String[] args)
284 System.out.println("Hello Java world!\n");
288 <file name="src/Example3.java">
289 public class Example3
291 public static void main(String[] args)
293 System.out.println("Hello Java world!\n");
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:
308 <scons_output example="java_jar1" suffix="1">
309 <scons_output_command>scons -Q</scons_output_command>
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:
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)
336 <file name="prog1/Example1.java">
337 public class Example1
339 public static void main(String[] args)
341 System.out.println("Hello Java world!\n");
345 <file name="prog1/Example2.java">
346 public class Example2
348 public static void main(String[] args)
350 System.out.println("Hello Java world!\n");
354 <file name="prog2/Example3.java">
355 public class Example3
357 public static void main(String[] args)
359 System.out.println("Hello Java world!\n");
363 <file name="prog2/Example4.java">
364 public class Example4
366 public static void main(String[] args)
368 System.out.println("Hello Java world!\n");
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:
384 <scons_output example="java_jar2" suffix="1">
385 <scons_output_command>scons -Q</scons_output_command>
391 <title>Building C Header and Stub Files: the &b-JavaH; Builder</title>
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:
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)
408 <file name="src/pkg/sub/Example1.java">
410 public class Example1
412 public static void main(String[] args)
417 <file name="src/pkg/sub/Example2.java">
419 public class Example2
421 public static void main(String[] args)
426 <file name="src/pkg/sub/Example3.java">
428 public class Example3
430 public static void main(String[] args)
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.
444 gets converted into the <option>-d</option>
445 when &SCons; runs &javah;:
449 <scons_output example="java_javah" suffix="1">
450 <scons_output_command>scons -Q</scons_output_command>
457 will generate the header files
458 <filename>native/pkg_sub_Example1.h</filename>,
459 <filename>native/pkg_sub_Example2.h</filename>
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;.
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.
482 &cv-link-JAVACLASSDIR; construction variable
483 when calling &b-JavaH;:
487 <scons_example name="java_JAVACLASSDIR">
488 <file name="SConstruct" printme="1">
489 Java(target='classes', source='src/pkg/sub')
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')
497 <file name="src/pkg/sub/Example1.java">
499 public class Example1
501 public static void main(String[] args)
506 <file name="src/pkg/sub/Example2.java">
508 public class Example2
510 public static void main(String[] args)
515 <file name="src/pkg/sub/Example3.java">
517 public class Example3
519 public static void main(String[] args)
528 The &cv-JAVACLASSDIR; value then
529 gets converted into the <option>-classpath</option>
530 when &SCons; runs &javah;:
534 <scons_output example="java_JAVACLASSDIR" suffix="1">
535 <scons_output_command>scons -Q</scons_output_command>
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:
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)
552 <file name="src/pkg/sub/Example1.java">
554 public class Example1
556 public static void main(String[] args)
561 <file name="src/pkg/sub/Example2.java">
563 public class Example2
565 public static void main(String[] args)
570 <file name="src/pkg/sub/Example3.java">
572 public class Example3
574 public static void main(String[] args)
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:
594 <scons_output example="java_javah_file" suffix="1">
595 <scons_output_command>scons -Q</scons_output_command>
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.
612 <title>Building RMI Stub and Skeleton Class Files: the &b-RMIC; Builder</title>
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
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)
632 <file name="src/pkg/sub/Example1.java">
634 public class Example1
636 public static void main(String[] args)
641 <file name="src/pkg/sub/Example2.java">
643 public class Example2
645 public static void main(String[] args)
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
661 <scons_output example="java_RMIC" suffix="1">
662 <scons_output_command>scons -Q</scons_output_command>
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>.