Issue 1086: add support for generic batch build actions, and
[scons.git] / doc / user / java.in
1 <!--
2
3   __COPYRIGHT__
4
5   Permission is hereby granted, free of charge, to any person obtaining
6   a copy of this software and associated documentation files (the
7   "Software"), to deal in the Software without restriction, including
8   without limitation the rights to use, copy, modify, merge, publish,
9   distribute, sublicense, and/or sell copies of the Software, and to
10   permit persons to whom the Software is furnished to do so, subject to
11   the following conditions:
12
13   The above copyright notice and this permission notice shall be included
14   in all copies or substantial portions of the Software.
15
16   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17   KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18   WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 -->
25
26   <para>
27
28   So far, we've been using examples of
29   building C and C++ programs
30   to demonstrate the features of &SCons;.
31   &SCons; also supports building Java programs,
32   but Java builds are handled slightly differently,
33   which reflects the ways in which
34   the Java compiler and tools
35   build programs differently than
36   other languages' tool chains.
37
38   </para>
39
40   <section>
41   <title>Building Java Class Files:  the &b-Java; Builder</title>
42
43     <para>
44
45     The basic activity when programming in Java,
46     of course, is to take one or more <filename>.java</filename> files
47     containing Java source code
48     and to call the Java compiler
49     to turn them into one or more
50     <filename>.class</filename> files.
51     In &SCons;, you do this
52     by giving the &b-link-Java; Builder
53     a target directory in which
54     to put the <filename>.class</filename> files,
55     and a source directory that contains
56     the <filename>.java</filename> files:
57
58     </para>
59
60     <scons_example name="java">
61       <file name="SConstruct" printme="1">
62       Java('classes', 'src')
63       </file>
64       <file name="src/Example1.java">
65       public class Example1
66       {
67         public static void main(String[] args)
68         {
69           System.out.println("Hello Java world!\n");
70         }
71       }
72       </file>
73       <file name="src/Example2.java">
74       public class Example2
75       {
76         public static void main(String[] args)
77         {
78           System.out.println("Hello Java world!\n");
79         }
80       }
81       </file>
82       <file name="src/Example3.java">
83       public class Example3
84       {
85         public static void main(String[] args)
86         {
87           System.out.println("Hello Java world!\n");
88         }
89       }
90       </file>
91     </scons_example>
92
93     <para>
94
95     If the <filename>src</filename> directory contains
96     three <filename>.java</filename> source files,
97     then running &SCons; might look like this:
98
99     </para>
100
101     <scons_output example="java">
102       <scons_output_command>scons -Q</scons_output_command>
103     </scons_output>
104
105     <para>
106
107     &SCons; will actually search the <filename>src</filename>
108     directory tree for all of the <filename>.java</filename> files.
109     The Java compiler will then create the
110     necessary class files in the <filename>classes</filename> subdirectory,
111     based on the class names found in the <filename>.java</filename> files.
112
113     </para>
114
115   </section>
116
117   <section>
118   <title>How &SCons; Handles Java Dependencies</title>
119
120     <para>
121
122     In addition to searching the source directory for
123     <filename>.java</filename> files,
124     &SCons; actually runs the <filename>.java</filename> files
125     through a stripped-down Java parser that figures out
126     what classes are defined.
127     In other words, &SCons; knows,
128     without you having to tell it,
129     what <filename>.class</filename> files
130     will be produced by the &javac; call.
131     So our one-liner example from the preceding section:
132
133     </para>
134
135     <scons_example name="java-classes">
136       <file name="SConstruct" printme="1">
137       Java('classes', 'src')
138       </file>
139       <file name="src/Example1.java">
140       public class Example1
141       {
142         public static void main(String[] args)
143         {
144           System.out.println("Hello Java world!\n");
145         }
146       }
147       public class AdditionalClass1
148       {
149         public static void main(String[] args)
150         {
151           System.out.println("Hello Java world!\n");
152         }
153       }
154       </file>
155       <file name="src/Example2.java">
156       public class Example2
157       {
158         class Inner2 {
159           public static void main(String[] args)
160           {
161             System.out.println("Hello Java world!\n");
162           }
163         }
164       }
165       </file>
166       <file name="src/Example3.java">
167       public class Example3
168       {
169         public static void main(String[] args)
170         {
171           System.out.println("Hello Java world!\n");
172         }
173       }
174       public class AdditionalClass3
175       {
176         public static void main(String[] args)
177         {
178           System.out.println("Hello Java world!\n");
179         }
180       }
181       </file>
182     </scons_example>
183
184     <para>
185
186     Will not only tell you reliably
187     that the <filename>.class</filename> files
188     in the <filename>classes</filename> subdirectory 
189     are up-to-date:
190
191     </para>
192
193     <scons_output example="java-classes">
194       <scons_output_command>scons -Q</scons_output_command>
195       <scons_output_command>scons -Q classes</scons_output_command>
196     </scons_output>
197
198     <para>
199
200     But it will also remove all of the generated
201     <filename>.class</filename> files,
202     even for inner classes,
203     without you having to specify them manually.
204     For example, if our
205     <filename>Example1.java</filename>
206     and
207     <filename>Example3.java</filename>
208     files both define additional classes,
209     and the class defined in <filename>Example2.java</filename>
210     has an inner class,
211     running <userinput>scons -c</userinput>
212     will clean up all of those <filename>.class</filename> files
213     as well:
214
215     </para>
216
217     <scons_output example="java-classes">
218       <scons_output_command>scons -Q</scons_output_command>
219       <scons_output_command>scons -Q -c classes</scons_output_command>
220     </scons_output>
221
222   </section>
223
224   <section>
225   <title>Building Java Archive (<filename>.jar</filename>) Files:  the &b-Jar; Builder</title>
226
227     <para>
228
229     After building the class files,
230     it's common to collect them into
231     a Java archive (<filename>.jar</filename>) file,
232     which you do by calling the &b-link-Jar; Builder method.
233     If you want to just collect all of the
234     class files within a subdirectory,
235     you can just specify that subdirectory
236     as the &b-Jar; source:
237
238     </para>
239
240     <scons_example name="jar1">
241       <file name="SConstruct" printme="1">
242       Java(target = 'classes', source = 'src')
243       Jar(target = 'test.jar', source = 'classes')
244       </file>
245       <file name="src/Example1.java">
246       public class Example1
247       {
248         public static void main(String[] args)
249         {
250           System.out.println("Hello Java world!\n");
251         }
252       }
253       </file>
254       <file name="src/Example2.java">
255       public class Example2
256       {
257         public static void main(String[] args)
258         {
259           System.out.println("Hello Java world!\n");
260         }
261       }
262       </file>
263       <file name="src/Example3.java">
264       public class Example3
265       {
266         public static void main(String[] args)
267         {
268           System.out.println("Hello Java world!\n");
269         }
270       }
271       </file>
272     </scons_example>
273
274     <para>
275
276     &SCons; will then pass that directory
277     to the &jar; command,
278     which will collect all of the underlying
279     <filename>.class</filename> files:
280
281     </para>
282
283     <scons_output example="jar1">
284       <scons_output_command>scons -Q</scons_output_command>
285     </scons_output>
286
287     <para>
288
289     If you want to keep all of the
290     <filename>.class</filename> files
291     for multiple programs in one location,
292     and only archive some of them in
293     each <filename>.jar</filename> file,
294     you can pass the &b-Jar; builder a
295     list of files as its source.
296     It's extremely simple to create multiple
297     <filename>.jar</filename> files this way,
298     using the lists of target class files created
299     by calls to the &b-link-Java; builder
300     as sources to the various &b-Jar; calls:
301
302     </para>
303
304     <scons_example name="jar2">
305       <file name="SConstruct" printme="1">
306       prog1_class_files = Java(target = 'classes', source = 'prog1')
307       prog2_class_files = Java(target = 'classes', source = 'prog2')
308       Jar(target = 'prog1.jar', source = prog1_class_files)
309       Jar(target = 'prog2.jar', source = prog2_class_files)
310       </file>
311       <file name="prog1/Example1.java">
312       public class Example1
313       {
314         public static void main(String[] args)
315         {
316           System.out.println("Hello Java world!\n");
317         }
318       }
319       </file>
320       <file name="prog1/Example2.java">
321       public class Example2
322       {
323         public static void main(String[] args)
324         {
325           System.out.println("Hello Java world!\n");
326         }
327       }
328       </file>
329       <file name="prog2/Example3.java">
330       public class Example3
331       {
332         public static void main(String[] args)
333         {
334           System.out.println("Hello Java world!\n");
335         }
336       }
337       </file>
338       <file name="prog2/Example4.java">
339       public class Example4
340       {
341         public static void main(String[] args)
342         {
343           System.out.println("Hello Java world!\n");
344         }
345       }
346       </file>
347     </scons_example>
348
349     <para>
350
351     This will then create
352     <filename>prog1.jar</filename>
353     and <filename>prog2.jar</filename>
354     next to the subdirectories
355     that contain their <filename>.java</filename> files:
356
357     </para>
358
359     <scons_output example="jar2">
360       <scons_output_command>scons -Q</scons_output_command>
361     </scons_output>
362
363   </section>
364
365   <section>
366   <title>Building C Header and Stub Files:  the &b-JavaH; Builder</title>
367
368     <para>
369
370     You can generate C header and source files
371     for implementing native methods,
372     by using the &b-link-JavaH; Builder.
373     There are several ways of using the &JavaH Builder.
374     One typical invocation might look like:
375
376     </para>
377
378     <scons_example name="javah">
379       <file name="SConstruct" printme="1">
380       classes = Java(target = 'classes', source = 'src/pkg/sub')
381       JavaH(target = 'native', source = classes)
382       </file>
383       <file name="src/pkg/sub/Example1.java">
384       package pkg.sub;
385       public class Example1
386       {
387         public static void main(String[] args)
388         {
389         }
390       }
391       </file>
392       <file name="src/pkg/sub/Example2.java">
393       package pkg.sub;
394       public class Example2
395       {
396         public static void main(String[] args)
397         {
398         }
399       }
400       </file>
401       <file name="src/pkg/sub/Example3.java">
402       package pkg.sub;
403       public class Example3
404       {
405         public static void main(String[] args)
406         {
407         }
408       }
409       </file>
410     </scons_example>
411
412     <para>
413
414     The source is a list of class files generated by the
415     call to the &b-link-Java; Builder,
416     and the target is the output directory in
417     which we want the C header files placed.
418     The target
419     gets converted into the <option>-d</option>
420     when &SCons; runs &javah;:
421
422     </para>
423
424     <scons_output example="javah">
425       <scons_output_command>scons -Q</scons_output_command>
426     </scons_output>
427
428     <para>
429
430     In this case,
431     the call to &javah;
432     will generate the header files
433     <filename>native/pkg_sub_Example1.h</filename>,
434     <filename>native/pkg_sub_Example2.h</filename>
435     and
436     <filename>native/pkg_sub_Example3.h</filename>.
437     Notice that &SCons; remembered that the class
438     files were generated with a target directory of
439     <filename>classes</filename>,
440     and that it then specified that target directory
441     as the <option>-classpath</option> option
442     to the call to &javah;.
443
444     </para>
445
446     <para>
447
448     Although it's more convenient to use
449     the list of class files returned by
450     the &b-Java; Builder
451     as the source of a call to the &b-JavaH; Builder,
452     you <emphasis>can</emphasis>
453     specify the list of class files
454     by hand, if you prefer.
455     If you do,
456     you need to set the
457     &cv-link-JAVACLASSDIR; construction variable
458     when calling &b-JavaH;:
459
460     </para>
461
462     <scons_example name="JAVACLASSDIR">
463       <file name="SConstruct" printme="1">
464       Java(target = 'classes', source = 'src/pkg/sub')
465       class_file_list = ['classes/pkg/sub/Example1.class',
466                          'classes/pkg/sub/Example2.class',
467                          'classes/pkg/sub/Example3.class']
468       JavaH(target = 'native', source = class_file_list, JAVACLASSDIR = 'classes')
469       </file>
470       <file name="src/pkg/sub/Example1.java">
471       package pkg.sub;
472       public class Example1
473       {
474         public static void main(String[] args)
475         {
476         }
477       }
478       </file>
479       <file name="src/pkg/sub/Example2.java">
480       package pkg.sub;
481       public class Example2
482       {
483         public static void main(String[] args)
484         {
485         }
486       }
487       </file>
488       <file name="src/pkg/sub/Example3.java">
489       package pkg.sub;
490       public class Example3
491       {
492         public static void main(String[] args)
493         {
494         }
495       }
496       </file>
497     </scons_example>
498
499     <para>
500
501     The &cv-JAVACLASSDIR; value then
502     gets converted into the <option>-classpath</option>
503     when &SCons; runs &javah;:
504
505     </para>
506
507     <scons_output example="JAVACLASSDIR">
508       <scons_output_command>scons -Q</scons_output_command>
509     </scons_output>
510
511     <para>
512
513     Lastly, if you don't want a separate header file
514     generated for each source file,
515     you can specify an explicit File Node
516     as the target of the &b-JavaH; Builder:
517
518     </para>
519
520     <scons_example name="javah_file">
521       <file name="SConstruct" printme="1">
522       classes = Java(target = 'classes', source = 'src/pkg/sub')
523       JavaH(target = File('native.h'), source = classes)
524       </file>
525       <file name="src/pkg/sub/Example1.java">
526       package pkg.sub;
527       public class Example1
528       {
529         public static void main(String[] args)
530         {
531         }
532       }
533       </file>
534       <file name="src/pkg/sub/Example2.java">
535       package pkg.sub;
536       public class Example2
537       {
538         public static void main(String[] args)
539         {
540         }
541       }
542       </file>
543       <file name="src/pkg/sub/Example3.java">
544       package pkg.sub;
545       public class Example3
546       {
547         public static void main(String[] args)
548         {
549         }
550       }
551       </file>
552     </scons_example>
553
554     <para>
555
556     Because &SCons; assumes by default
557     that the target of the &b-JavaH; builder is a directory,
558     you need to use the &File; function
559     to make sure that &SCons; doesn't
560     create a directory named <filename>native.h</filename>.
561     When a file is used, though,
562     &SCons; correctly converts the file name
563     into the &javah; <option>-o</option> option:
564
565     </para>
566
567     <scons_output example="javah_file">
568       <scons_output_command>scons -Q</scons_output_command>
569     </scons_output>
570
571   </section>
572
573   <section>
574   <title>Building RMI Stub and Skeleton Class Files:  the &b-RMIC; Builder</title>
575
576     <para>
577
578     You can generate Remote Method Invocation stubs
579     by using the &b-link-RMIC; Builder.
580     The source is a list of directories,
581     typically returned by a call to the &b-link-Java; Builder,
582     and the target is an output directory
583     where the <filename>_Stub.class</filename>
584     and <filename>_Skel.class</filename> files will
585     be placed:
586
587     </para>
588
589     <scons_example name="RMIC">
590       <file name="SConstruct" printme="1">
591       classes = Java(target = 'classes', source = 'src/pkg/sub')
592       RMIC(target = 'outdir', source = classes)
593       </file>
594       <file name="src/pkg/sub/Example1.java">
595       package pkg.sub;
596       public class Example1
597       {
598         public static void main(String[] args)
599         {
600         }
601       }
602       </file>
603       <file name="src/pkg/sub/Example2.java">
604       package pkg.sub;
605       public class Example2
606       {
607         public static void main(String[] args)
608         {
609         }
610       }
611       </file>
612     </scons_example>
613
614     <para>
615
616     As it did with the &b-link-JavaH; Builder,
617     &SCons; remembers the class directory
618     and passes it as the <option>-classpath</option> option
619     to &rmic:
620
621     </para>
622
623     <scons_output example="RMIC">
624       <scons_output_command>scons -Q</scons_output_command>
625     </scons_output>
626
627     <para>
628
629     This example would generate the files
630     <filename>outdir/pkg/sub/Example1_Skel.class</filename>,
631     <filename>outdir/pkg/sub/Example1_Stub.class</filename>,
632     <filename>outdir/pkg/sub/Example2_Skel.class</filename> and
633     <filename>outdir/pkg/sub/Example2_Stub.class</filename>.
634
635     </para>
636
637   </section>