1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs.compilers;
  18. import org.apache.tools.ant.BuildException;
  19. import org.apache.tools.ant.Project;
  20. import org.apache.tools.ant.Task;
  21. import org.apache.tools.ant.util.JavaEnvUtils;
  22. /**
  23. * Creates the necessary compiler adapter, given basic criteria.
  24. *
  25. * @since Ant 1.3
  26. */
  27. public class CompilerAdapterFactory {
  28. private static final String MODERN_COMPILER = "com.sun.tools.javac.Main";
  29. /** This is a singleton -- can't create instances!! */
  30. private CompilerAdapterFactory() {
  31. }
  32. /**
  33. * Based on the parameter passed in, this method creates the necessary
  34. * factory desired.
  35. *
  36. * The current mapping for compiler names are as follows:
  37. * <ul><li>jikes = jikes compiler
  38. * <li>classic, javac1.1, javac1.2 = the standard compiler from JDK
  39. * 1.1/1.2
  40. * <li>modern, javac1.3, javac1.4, javac1.5 = the compiler of JDK 1.3+
  41. * <li>jvc, microsoft = the command line compiler from Microsoft's SDK
  42. * for Java / Visual J++
  43. * <li>kjc = the kopi compiler</li>
  44. * <li>gcj = the gcj compiler from gcc</li>
  45. * <li>sj, symantec = the Symantec Java compiler</li>
  46. * <li><i>a fully qualified classname</i> = the name of a compiler
  47. * adapter
  48. * </ul>
  49. *
  50. * @param compilerType either the name of the desired compiler, or the
  51. * full classname of the compiler's adapter.
  52. * @param task a task to log through.
  53. * @throws BuildException if the compiler type could not be resolved into
  54. * a compiler adapter.
  55. */
  56. public static CompilerAdapter getCompiler(String compilerType, Task task)
  57. throws BuildException {
  58. boolean isClassicCompilerSupported = true;
  59. //as new versions of java come out, add them to this test
  60. if (!JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)
  61. && !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2)
  62. && !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3)) {
  63. isClassicCompilerSupported = false;
  64. }
  65. if (compilerType.equalsIgnoreCase("jikes")) {
  66. return new Jikes();
  67. }
  68. if (compilerType.equalsIgnoreCase("extJavac")) {
  69. return new JavacExternal();
  70. }
  71. if (compilerType.equalsIgnoreCase("classic")
  72. || compilerType.equalsIgnoreCase("javac1.1")
  73. || compilerType.equalsIgnoreCase("javac1.2")) {
  74. if (isClassicCompilerSupported) {
  75. return new Javac12();
  76. } else {
  77. task.log("This version of java does "
  78. + "not support the classic "
  79. + "compiler; upgrading to modern",
  80. Project.MSG_WARN);
  81. compilerType = "modern";
  82. }
  83. }
  84. //on java<=1.3 the modern falls back to classic if it is not found
  85. //but on java>=1.4 we just bail out early
  86. if (compilerType.equalsIgnoreCase("modern")
  87. || compilerType.equalsIgnoreCase("javac1.3")
  88. || compilerType.equalsIgnoreCase("javac1.4")
  89. || compilerType.equalsIgnoreCase("javac1.5")) {
  90. // does the modern compiler exist?
  91. if (doesModernCompilerExist()) {
  92. return new Javac13();
  93. } else {
  94. if (isClassicCompilerSupported) {
  95. task.log("Modern compiler not found - looking for "
  96. + "classic compiler", Project.MSG_WARN);
  97. return new Javac12();
  98. } else {
  99. throw new BuildException("Unable to find a javac "
  100. + "compiler;\n"
  101. + MODERN_COMPILER
  102. + " is not on the "
  103. + "classpath.\n"
  104. + "Perhaps JAVA_HOME does not"
  105. + " point to the JDK");
  106. }
  107. }
  108. }
  109. if (compilerType.equalsIgnoreCase("jvc")
  110. || compilerType.equalsIgnoreCase("microsoft")) {
  111. return new Jvc();
  112. }
  113. if (compilerType.equalsIgnoreCase("kjc")) {
  114. return new Kjc();
  115. }
  116. if (compilerType.equalsIgnoreCase("gcj")) {
  117. return new Gcj();
  118. }
  119. if (compilerType.equalsIgnoreCase("sj")
  120. || compilerType.equalsIgnoreCase("symantec")) {
  121. return new Sj();
  122. }
  123. return resolveClassName(compilerType);
  124. }
  125. /**
  126. * query for the Modern compiler existing
  127. * @return true if classic os on the classpath
  128. */
  129. private static boolean doesModernCompilerExist() {
  130. try {
  131. Class.forName(MODERN_COMPILER);
  132. return true;
  133. } catch (ClassNotFoundException cnfe) {
  134. try {
  135. CompilerAdapterFactory.class.getClassLoader().loadClass(MODERN_COMPILER);
  136. return true;
  137. } catch (ClassNotFoundException cnfe2) {
  138. }
  139. }
  140. return false;
  141. }
  142. /**
  143. * Tries to resolve the given classname into a compiler adapter.
  144. * Throws a fit if it can't.
  145. *
  146. * @param className The fully qualified classname to be created.
  147. * @throws BuildException This is the fit that is thrown if className
  148. * isn't an instance of CompilerAdapter.
  149. */
  150. private static CompilerAdapter resolveClassName(String className)
  151. throws BuildException {
  152. try {
  153. Class c = Class.forName(className);
  154. Object o = c.newInstance();
  155. return (CompilerAdapter) o;
  156. } catch (ClassNotFoundException cnfe) {
  157. throw new BuildException("Compiler Adapter '" + className
  158. + "' can\'t be found.", cnfe);
  159. } catch (ClassCastException cce) {
  160. throw new BuildException(className + " isn\'t the classname of "
  161. + "a compiler adapter.", cce);
  162. } catch (Throwable t) {
  163. // for all other possibilities
  164. throw new BuildException("Compiler Adapter " + className
  165. + " caused an interesting exception.", t);
  166. }
  167. }
  168. }