001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant.taskdefs.compilers;
020:
021: //Java5 style
022: //import static org.apache.tools.ant.util.StringUtils.LINE_SEP;
023:
024: import java.io.File;
025: import java.io.FileWriter;
026: import java.io.IOException;
027: import java.io.PrintWriter;
028: import org.apache.tools.ant.BuildException;
029: import org.apache.tools.ant.Location;
030: import org.apache.tools.ant.Project;
031: import org.apache.tools.ant.taskdefs.Execute;
032: import org.apache.tools.ant.taskdefs.Javac;
033: import org.apache.tools.ant.taskdefs.LogStreamHandler;
034: import org.apache.tools.ant.types.Commandline;
035: import org.apache.tools.ant.types.Path;
036: import org.apache.tools.ant.util.FileUtils;
037: import org.apache.tools.ant.util.StringUtils;
038: import org.apache.tools.ant.util.JavaEnvUtils;
039: import org.apache.tools.ant.taskdefs.condition.Os;
040:
041: /**
042: * This is the default implementation for the CompilerAdapter interface.
043: * Currently, this is a cut-and-paste of the original javac task.
044: *
045: * @since Ant 1.3
046: */
047: public abstract class DefaultCompilerAdapter implements CompilerAdapter {
048: // CheckStyle:VisibilityModifier OFF - bc
049:
050: private static final FileUtils FILE_UTILS = FileUtils
051: .getFileUtils();
052:
053: protected Path src;
054: protected File destDir;
055: protected String encoding;
056: protected boolean debug = false;
057: protected boolean optimize = false;
058: protected boolean deprecation = false;
059: protected boolean depend = false;
060: protected boolean verbose = false;
061: protected String target;
062: protected Path bootclasspath;
063: protected Path extdirs;
064: protected Path compileClasspath;
065: protected Path compileSourcepath;
066: protected Project project;
067: protected Location location;
068: protected boolean includeAntRuntime;
069: protected boolean includeJavaRuntime;
070: protected String memoryInitialSize;
071: protected String memoryMaximumSize;
072:
073: protected File[] compileList;
074: protected Javac attributes;
075:
076: //must keep for subclass BC, though unused:
077: // CheckStyle:ConstantNameCheck OFF - bc
078: protected static final String lSep = StringUtils.LINE_SEP;
079:
080: // CheckStyle:ConstantNameCheck ON
081: // CheckStyle:VisibilityModifier ON
082:
083: /**
084: * Set the Javac instance which contains the configured compilation
085: * attributes.
086: *
087: * @param attributes a configured Javac task.
088: */
089: public void setJavac(Javac attributes) {
090: this .attributes = attributes;
091: src = attributes.getSrcdir();
092: destDir = attributes.getDestdir();
093: encoding = attributes.getEncoding();
094: debug = attributes.getDebug();
095: optimize = attributes.getOptimize();
096: deprecation = attributes.getDeprecation();
097: depend = attributes.getDepend();
098: verbose = attributes.getVerbose();
099: target = attributes.getTarget();
100: bootclasspath = attributes.getBootclasspath();
101: extdirs = attributes.getExtdirs();
102: compileList = attributes.getFileList();
103: compileClasspath = attributes.getClasspath();
104: compileSourcepath = attributes.getSourcepath();
105: project = attributes.getProject();
106: location = attributes.getLocation();
107: includeAntRuntime = attributes.getIncludeantruntime();
108: includeJavaRuntime = attributes.getIncludejavaruntime();
109: memoryInitialSize = attributes.getMemoryInitialSize();
110: memoryMaximumSize = attributes.getMemoryMaximumSize();
111: }
112:
113: /**
114: * Get the Javac task instance associated with this compiler adapter
115: *
116: * @return the configured Javac task instance used by this adapter.
117: */
118: public Javac getJavac() {
119: return attributes;
120: }
121:
122: /**
123: * Get the project this compiler adapter was created in.
124: * @return the owner project
125: * @since Ant 1.6
126: */
127: protected Project getProject() {
128: return project;
129: }
130:
131: /**
132: * Builds the compilation classpath.
133: * @return the compilation class path
134: */
135: protected Path getCompileClasspath() {
136: Path classpath = new Path(project);
137:
138: // add dest dir to classpath so that previously compiled and
139: // untouched classes are on classpath
140:
141: if (destDir != null) {
142: classpath.setLocation(destDir);
143: }
144:
145: // Combine the build classpath with the system classpath, in an
146: // order determined by the value of build.sysclasspath
147:
148: Path cp = compileClasspath;
149: if (cp == null) {
150: cp = new Path(project);
151: }
152: if (includeAntRuntime) {
153: classpath.addExisting(cp.concatSystemClasspath("last"));
154: } else {
155: classpath.addExisting(cp.concatSystemClasspath("ignore"));
156: }
157:
158: if (includeJavaRuntime) {
159: classpath.addJavaRuntime();
160: }
161:
162: return classpath;
163: }
164:
165: /**
166: * Get the command line arguments for the switches.
167: * @param cmd the command line
168: * @return the command line
169: */
170: protected Commandline setupJavacCommandlineSwitches(Commandline cmd) {
171: return setupJavacCommandlineSwitches(cmd, false);
172: }
173:
174: /**
175: * Does the command line argument processing common to classic and
176: * modern. Doesn't add the files to compile.
177: * @param cmd the command line
178: * @param useDebugLevel if true set set the debug level with the -g switch
179: * @return the command line
180: */
181: protected Commandline setupJavacCommandlineSwitches(
182: Commandline cmd, boolean useDebugLevel) {
183: Path classpath = getCompileClasspath();
184: // For -sourcepath, use the "sourcepath" value if present.
185: // Otherwise default to the "srcdir" value.
186: Path sourcepath = null;
187: if (compileSourcepath != null) {
188: sourcepath = compileSourcepath;
189: } else {
190: sourcepath = src;
191: }
192:
193: String memoryParameterPrefix = assumeJava11() ? "-J-" : "-J-X";
194: if (memoryInitialSize != null) {
195: if (!attributes.isForkedJavac()) {
196: attributes.log("Since fork is false, ignoring "
197: + "memoryInitialSize setting.",
198: Project.MSG_WARN);
199: } else {
200: cmd.createArgument().setValue(
201: memoryParameterPrefix + "ms"
202: + memoryInitialSize);
203: }
204: }
205:
206: if (memoryMaximumSize != null) {
207: if (!attributes.isForkedJavac()) {
208: attributes.log("Since fork is false, ignoring "
209: + "memoryMaximumSize setting.",
210: Project.MSG_WARN);
211: } else {
212: cmd.createArgument().setValue(
213: memoryParameterPrefix + "mx"
214: + memoryMaximumSize);
215: }
216: }
217:
218: if (attributes.getNowarn()) {
219: cmd.createArgument().setValue("-nowarn");
220: }
221:
222: if (deprecation) {
223: cmd.createArgument().setValue("-deprecation");
224: }
225:
226: if (destDir != null) {
227: cmd.createArgument().setValue("-d");
228: cmd.createArgument().setFile(destDir);
229: }
230:
231: cmd.createArgument().setValue("-classpath");
232:
233: // Just add "sourcepath" to classpath ( for JDK1.1 )
234: // as well as "bootclasspath" and "extdirs"
235: if (assumeJava11()) {
236: Path cp = new Path(project);
237:
238: Path bp = getBootClassPath();
239: if (bp.size() > 0) {
240: cp.append(bp);
241: }
242:
243: if (extdirs != null) {
244: cp.addExtdirs(extdirs);
245: }
246: cp.append(classpath);
247: cp.append(sourcepath);
248: cmd.createArgument().setPath(cp);
249: } else {
250: cmd.createArgument().setPath(classpath);
251: // If the buildfile specifies sourcepath="", then don't
252: // output any sourcepath.
253: if (sourcepath.size() > 0) {
254: cmd.createArgument().setValue("-sourcepath");
255: cmd.createArgument().setPath(sourcepath);
256: }
257: if (target != null) {
258: cmd.createArgument().setValue("-target");
259: cmd.createArgument().setValue(target);
260: }
261:
262: Path bp = getBootClassPath();
263: if (bp.size() > 0) {
264: cmd.createArgument().setValue("-bootclasspath");
265: cmd.createArgument().setPath(bp);
266: }
267:
268: if (extdirs != null && extdirs.size() > 0) {
269: cmd.createArgument().setValue("-extdirs");
270: cmd.createArgument().setPath(extdirs);
271: }
272: }
273:
274: if (encoding != null) {
275: cmd.createArgument().setValue("-encoding");
276: cmd.createArgument().setValue(encoding);
277: }
278: if (debug) {
279: if (useDebugLevel && !assumeJava11()) {
280: String debugLevel = attributes.getDebugLevel();
281: if (debugLevel != null) {
282: cmd.createArgument().setValue("-g:" + debugLevel);
283: } else {
284: cmd.createArgument().setValue("-g");
285: }
286: } else {
287: cmd.createArgument().setValue("-g");
288: }
289: } else if (getNoDebugArgument() != null) {
290: cmd.createArgument().setValue(getNoDebugArgument());
291: }
292: if (optimize) {
293: cmd.createArgument().setValue("-O");
294: }
295:
296: if (depend) {
297: if (assumeJava11()) {
298: cmd.createArgument().setValue("-depend");
299: } else if (assumeJava12()) {
300: cmd.createArgument().setValue("-Xdepend");
301: } else {
302: attributes.log(
303: "depend attribute is not supported by the "
304: + "modern compiler", Project.MSG_WARN);
305: }
306: }
307:
308: if (verbose) {
309: cmd.createArgument().setValue("-verbose");
310: }
311:
312: addCurrentCompilerArgs(cmd);
313:
314: return cmd;
315: }
316:
317: /**
318: * Does the command line argument processing for modern. Doesn't
319: * add the files to compile.
320: * @param cmd the command line
321: * @return the command line
322: */
323: protected Commandline setupModernJavacCommandlineSwitches(
324: Commandline cmd) {
325: setupJavacCommandlineSwitches(cmd, true);
326: if (attributes.getSource() != null && !assumeJava13()) {
327: cmd.createArgument().setValue("-source");
328: String source = attributes.getSource();
329: if ((assumeJava14() || assumeJava15())
330: && (source.equals("1.1") || source.equals("1.2"))) {
331: // support for -source 1.1 and -source 1.2 has been
332: // added with JDK 1.4.2 - and isn't present in 1.5.0 either
333: cmd.createArgument().setValue("1.3");
334: } else {
335: cmd.createArgument().setValue(source);
336: }
337: } else if ((assumeJava15() || assumeJava16())
338: && attributes.getTarget() != null) {
339: String t = attributes.getTarget();
340: if (t.equals("1.1") || t.equals("1.2") || t.equals("1.3")
341: || t.equals("1.4")) {
342: String s = t;
343: if (t.equals("1.1")) {
344: // 1.5.0 doesn't support -source 1.1
345: s = "1.2";
346: }
347: attributes.log("", Project.MSG_WARN);
348: attributes.log(" WARNING", Project.MSG_WARN);
349: attributes.log("", Project.MSG_WARN);
350: attributes
351: .log(
352: "The -source switch defaults to 1.5 in JDK 1.5 and 1.6.",
353: Project.MSG_WARN);
354: attributes.log("If you specify -target " + t
355: + " you now must also specify -source " + s
356: + ".", Project.MSG_WARN);
357: attributes.log("Ant will implicitly add -source " + s
358: + " for you. Please change your build file.",
359: Project.MSG_WARN);
360: cmd.createArgument().setValue("-source");
361: cmd.createArgument().setValue(s);
362: }
363: }
364: return cmd;
365: }
366:
367: /**
368: * Does the command line argument processing for modern and adds
369: * the files to compile as well.
370: * @return the command line
371: */
372: protected Commandline setupModernJavacCommand() {
373: Commandline cmd = new Commandline();
374: setupModernJavacCommandlineSwitches(cmd);
375:
376: logAndAddFilesToCompile(cmd);
377: return cmd;
378: }
379:
380: /**
381: * Set up the command line.
382: * @return the command line
383: */
384: protected Commandline setupJavacCommand() {
385: return setupJavacCommand(false);
386: }
387:
388: /**
389: * Does the command line argument processing for classic and adds
390: * the files to compile as well.
391: * @param debugLevelCheck if true set the debug level with the -g switch
392: * @return the command line
393: */
394: protected Commandline setupJavacCommand(boolean debugLevelCheck) {
395: Commandline cmd = new Commandline();
396: setupJavacCommandlineSwitches(cmd, debugLevelCheck);
397: logAndAddFilesToCompile(cmd);
398: return cmd;
399: }
400:
401: /**
402: * Logs the compilation parameters, adds the files to compile and logs the
403: * "niceSourceList"
404: * @param cmd the command line
405: */
406: protected void logAndAddFilesToCompile(Commandline cmd) {
407: attributes.log("Compilation " + cmd.describeArguments(),
408: Project.MSG_VERBOSE);
409:
410: StringBuffer niceSourceList = new StringBuffer("File");
411: if (compileList.length != 1) {
412: niceSourceList.append("s");
413: }
414: niceSourceList.append(" to be compiled:");
415:
416: niceSourceList.append(StringUtils.LINE_SEP);
417:
418: for (int i = 0; i < compileList.length; i++) {
419: String arg = compileList[i].getAbsolutePath();
420: cmd.createArgument().setValue(arg);
421: niceSourceList.append(" ");
422: niceSourceList.append(arg);
423: niceSourceList.append(StringUtils.LINE_SEP);
424: }
425:
426: attributes.log(niceSourceList.toString(), Project.MSG_VERBOSE);
427: }
428:
429: /**
430: * Do the compile with the specified arguments.
431: * @param args - arguments to pass to process on command line
432: * @param firstFileName - index of the first source file in args,
433: * if the index is negative, no temporary file will ever be
434: * created, but this may hit the command line length limit on your
435: * system.
436: * @return the exit code of the compilation
437: */
438: protected int executeExternalCompile(String[] args,
439: int firstFileName) {
440: return executeExternalCompile(args, firstFileName, true);
441: }
442:
443: /**
444: * Do the compile with the specified arguments.
445: * @param args - arguments to pass to process on command line
446: * @param firstFileName - index of the first source file in args,
447: * if the index is negative, no temporary file will ever be
448: * created, but this may hit the command line length limit on your
449: * system.
450: * @param quoteFiles - if set to true, filenames containing
451: * spaces will be quoted when they appear in the external file.
452: * This is necessary when running JDK 1.4's javac and probably
453: * others.
454: * @return the exit code of the compilation
455: *
456: * @since Ant 1.6
457: */
458: protected int executeExternalCompile(String[] args,
459: int firstFileName, boolean quoteFiles) {
460: String[] commandArray = null;
461: File tmpFile = null;
462:
463: try {
464: /*
465: * Many system have been reported to get into trouble with
466: * long command lines - no, not only Windows ;-).
467: *
468: * POSIX seems to define a lower limit of 4k, so use a temporary
469: * file if the total length of the command line exceeds this limit.
470: */
471: if (Commandline.toString(args).length() > 4096
472: && firstFileName >= 0) {
473: PrintWriter out = null;
474: try {
475: tmpFile = FILE_UTILS.createTempFile("files", "",
476: getJavac().getTempdir());
477: tmpFile.deleteOnExit();
478: out = new PrintWriter(new FileWriter(tmpFile));
479: for (int i = firstFileName; i < args.length; i++) {
480: if (quoteFiles && args[i].indexOf(" ") > -1) {
481: args[i] = args[i].replace(
482: File.separatorChar, '/');
483: out.println("\"" + args[i] + "\"");
484: } else {
485: out.println(args[i]);
486: }
487: }
488: out.flush();
489: commandArray = new String[firstFileName + 1];
490: System.arraycopy(args, 0, commandArray, 0,
491: firstFileName);
492: commandArray[firstFileName] = "@" + tmpFile;
493: } catch (IOException e) {
494: throw new BuildException(
495: "Error creating temporary file", e,
496: location);
497: } finally {
498: FileUtils.close(out);
499: }
500: } else {
501: commandArray = args;
502: }
503:
504: try {
505: Execute exe = new Execute(new LogStreamHandler(
506: attributes, Project.MSG_INFO, Project.MSG_WARN));
507: if (Os.isFamily("openvms")) {
508: //Use the VM launcher instead of shell launcher on VMS
509: //for java
510: exe.setVMLauncher(true);
511: }
512: exe.setAntRun(project);
513: exe.setWorkingDirectory(project.getBaseDir());
514: exe.setCommandline(commandArray);
515: exe.execute();
516: return exe.getExitValue();
517: } catch (IOException e) {
518: throw new BuildException("Error running " + args[0]
519: + " compiler", e, location);
520: }
521: } finally {
522: if (tmpFile != null) {
523: tmpFile.delete();
524: }
525: }
526: }
527:
528: /**
529: * Add extdirs to classpath
530: * @param classpath the classpath to use
531: * @deprecated since 1.5.x.
532: * Use org.apache.tools.ant.types.Path#addExtdirs instead.
533: */
534: protected void addExtdirsToClasspath(Path classpath) {
535: classpath.addExtdirs(extdirs);
536: }
537:
538: /**
539: * Adds the command line arguments specific to the current implementation.
540: * @param cmd the command line to use
541: */
542: protected void addCurrentCompilerArgs(Commandline cmd) {
543: cmd.addArguments(getJavac().getCurrentCompilerArgs());
544: }
545:
546: /**
547: * Shall we assume JDK 1.1 command line switches?
548: * @return true if jdk 1.1
549: * @since Ant 1.5
550: */
551: protected boolean assumeJava11() {
552: return "javac1.1".equals(attributes.getCompilerVersion());
553: }
554:
555: /**
556: * Shall we assume JDK 1.2 command line switches?
557: * @return true if jdk 1.2
558: * @since Ant 1.5
559: */
560: protected boolean assumeJava12() {
561: return "javac1.2".equals(attributes.getCompilerVersion())
562: || ("classic".equals(attributes.getCompilerVersion()) && JavaEnvUtils
563: .isJavaVersion(JavaEnvUtils.JAVA_1_2))
564: || ("extJavac".equals(attributes.getCompilerVersion()) && JavaEnvUtils
565: .isJavaVersion(JavaEnvUtils.JAVA_1_2));
566: }
567:
568: /**
569: * Shall we assume JDK 1.3 command line switches?
570: * @return true if jdk 1.3
571: * @since Ant 1.5
572: */
573: protected boolean assumeJava13() {
574: return "javac1.3".equals(attributes.getCompilerVersion())
575: || ("classic".equals(attributes.getCompilerVersion()) && JavaEnvUtils
576: .isJavaVersion(JavaEnvUtils.JAVA_1_3))
577: || ("modern".equals(attributes.getCompilerVersion()) && JavaEnvUtils
578: .isJavaVersion(JavaEnvUtils.JAVA_1_3))
579: || ("extJavac".equals(attributes.getCompilerVersion()) && JavaEnvUtils
580: .isJavaVersion(JavaEnvUtils.JAVA_1_3));
581: }
582:
583: /**
584: * Shall we assume JDK 1.4 command line switches?
585: * @return true if jdk 1.4
586: * @since Ant 1.6.3
587: */
588: protected boolean assumeJava14() {
589: return "javac1.4".equals(attributes.getCompilerVersion())
590: || ("classic".equals(attributes.getCompilerVersion()) && JavaEnvUtils
591: .isJavaVersion(JavaEnvUtils.JAVA_1_4))
592: || ("modern".equals(attributes.getCompilerVersion()) && JavaEnvUtils
593: .isJavaVersion(JavaEnvUtils.JAVA_1_4))
594: || ("extJavac".equals(attributes.getCompilerVersion()) && JavaEnvUtils
595: .isJavaVersion(JavaEnvUtils.JAVA_1_4));
596: }
597:
598: /**
599: * Shall we assume JDK 1.5 command line switches?
600: * @return true if JDK 1.5
601: * @since Ant 1.6.3
602: */
603: protected boolean assumeJava15() {
604: return "javac1.5".equals(attributes.getCompilerVersion())
605: || ("classic".equals(attributes.getCompilerVersion()) && JavaEnvUtils
606: .isJavaVersion(JavaEnvUtils.JAVA_1_5))
607: || ("modern".equals(attributes.getCompilerVersion()) && JavaEnvUtils
608: .isJavaVersion(JavaEnvUtils.JAVA_1_5))
609: || ("extJavac".equals(attributes.getCompilerVersion()) && JavaEnvUtils
610: .isJavaVersion(JavaEnvUtils.JAVA_1_5));
611: }
612:
613: /**
614: * Shall we assume JDK 1.6 command line switches?
615: * @return true if JDK 1.6
616: * @since Ant 1.7
617: */
618: protected boolean assumeJava16() {
619: return "javac1.6".equals(attributes.getCompilerVersion())
620: || ("classic".equals(attributes.getCompilerVersion()) && JavaEnvUtils
621: .isJavaVersion(JavaEnvUtils.JAVA_1_6))
622: || ("modern".equals(attributes.getCompilerVersion()) && JavaEnvUtils
623: .isJavaVersion(JavaEnvUtils.JAVA_1_6))
624: || ("extJavac".equals(attributes.getCompilerVersion()) && JavaEnvUtils
625: .isJavaVersion(JavaEnvUtils.JAVA_1_6));
626: }
627:
628: /**
629: * Combines a user specified bootclasspath with the system
630: * bootclasspath taking build.sysclasspath into account.
631: *
632: * @return a non-null Path instance that combines the user
633: * specified and the system bootclasspath.
634: */
635: protected Path getBootClassPath() {
636: Path bp = new Path(project);
637: if (bootclasspath != null) {
638: bp.append(bootclasspath);
639: }
640: return bp.concatSystemBootClasspath("ignore");
641: }
642:
643: /**
644: * The argument the compiler wants to see if the debug attribute
645: * has been set to false.
646: *
647: * <p>A return value of <code>null</code> means no argument at all.</p>
648: *
649: * @return "-g:none" unless we expect to invoke a JDK 1.1 compiler.
650: *
651: * @since Ant 1.6.3
652: */
653: protected String getNoDebugArgument() {
654: return assumeJava11() ? null : "-g:none";
655: }
656: }
|