summaryrefslogtreecommitdiff
path: root/src/main/org/apache/tools/ant/taskdefs/compilers/CompilerAdapterFactory.java
blob: 5a2b5d7c0468d9aa4ca9c0cb10a4a530edbfb101 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/* 
 * Copyright  2001-2004 Apache Software Foundation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 * 
 */

package org.apache.tools.ant.taskdefs.compilers;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.util.JavaEnvUtils;

/**
 * Creates the necessary compiler adapter, given basic criteria.
 *
 * @author <a href="mailto:jayglanville@home.com">J D Glanville</a>
 * @since Ant 1.3
 */
public class CompilerAdapterFactory {
    private static final String MODERN_COMPILER = "com.sun.tools.javac.Main";

    /** This is a singleton -- can't create instances!! */
    private CompilerAdapterFactory() {
    }

    /**
     * Based on the parameter passed in, this method creates the necessary
     * factory desired.
     *
     * The current mapping for compiler names are as follows:
     * <ul><li>jikes = jikes compiler
     * <li>classic, javac1.1, javac1.2 = the standard compiler from JDK
     * 1.1/1.2
     * <li>modern, javac1.3, javac1.4, javac1.5 = the compiler of JDK 1.3+
     * <li>jvc, microsoft = the command line compiler from Microsoft's SDK
     * for Java / Visual J++
     * <li>kjc = the kopi compiler</li>
     * <li>gcj = the gcj compiler from gcc</li>
     * <li>sj, symantec = the Symantec Java compiler</li>
     * <li><i>a fully qualified classname</i> = the name of a compiler
     * adapter
     * </ul>
     *
     * @param compilerType either the name of the desired compiler, or the
     * full classname of the compiler's adapter.
     * @param task a task to log through.
     * @throws BuildException if the compiler type could not be resolved into
     * a compiler adapter.
     */
    public static CompilerAdapter getCompiler(String compilerType, Task task)
        throws BuildException {
            boolean isClassicCompilerSupported = true;
            //as new versions of java come out, add them to this test
            if (!JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)
                && !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2)
                && !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3)) {
                isClassicCompilerSupported = false;
            }

            if (compilerType.equalsIgnoreCase("jikes")) {
                return new Jikes();
            }
            if (compilerType.equalsIgnoreCase("extJavac")) {
                return new JavacExternal();
            }
            if (compilerType.equalsIgnoreCase("classic")
                || compilerType.equalsIgnoreCase("javac1.1")
                || compilerType.equalsIgnoreCase("javac1.2")) {
                if (isClassicCompilerSupported) {
                    return new Javac12();
                } else {
                    task.log("This version of java does "
                                             + "not support the classic "
                                             + "compiler; upgrading to modern",
                                             Project.MSG_WARN);
                    compilerType = "modern";
                }
            }
            //on java<=1.3 the modern falls back to classic if it is not found
            //but on java>=1.4 we just bail out early
            if (compilerType.equalsIgnoreCase("modern")
                || compilerType.equalsIgnoreCase("javac1.3")
                || compilerType.equalsIgnoreCase("javac1.4")
                || compilerType.equalsIgnoreCase("javac1.5")) {
                // does the modern compiler exist?
                if (doesModernCompilerExist()) {
                    return new Javac13();
                } else {
                    if (isClassicCompilerSupported) {
                        task.log("Modern compiler not found - looking for "
                                 + "classic compiler", Project.MSG_WARN);
                        return new Javac12();
                    } else {
                        throw new BuildException("Unable to find a javac "
                                                 + "compiler;\n"
                                                 + MODERN_COMPILER
                                                 + " is not on the "
                                                 + "classpath.\n"
                                                 + "Perhaps JAVA_HOME does not"
                                                 + " point to the JDK");
                    }
                }
            }

            if (compilerType.equalsIgnoreCase("jvc")
                || compilerType.equalsIgnoreCase("microsoft")) {
                return new Jvc();
            }
            if (compilerType.equalsIgnoreCase("kjc")) {
                return new Kjc();
            }
            if (compilerType.equalsIgnoreCase("gcj")) {
                return new Gcj();
            }
            if (compilerType.equalsIgnoreCase("sj")
                || compilerType.equalsIgnoreCase("symantec")) {
                return new Sj();
            }
            return resolveClassName(compilerType);
        }

    /**
     * query for the Modern compiler existing
     * @return true if classic os on the classpath
     */
    private static boolean doesModernCompilerExist() {
        try {
            Class.forName(MODERN_COMPILER);
            return true;
        } catch (ClassNotFoundException cnfe) {
            try {
                CompilerAdapterFactory.class.getClassLoader().loadClass(MODERN_COMPILER);
                return true;
            } catch (ClassNotFoundException cnfe2) {
            }
        }
        return false;
    }

    /**
     * Tries to resolve the given classname into a compiler adapter.
     * Throws a fit if it can't.
     *
     * @param className The fully qualified classname to be created.
     * @throws BuildException This is the fit that is thrown if className
     * isn't an instance of CompilerAdapter.
     */
    private static CompilerAdapter resolveClassName(String className)
        throws BuildException {
        try {
            Class c = Class.forName(className);
            Object o = c.newInstance();
            return (CompilerAdapter) o;
        } catch (ClassNotFoundException cnfe) {
            throw new BuildException("Compiler Adapter '" + className
                    + "' can\'t be found.", cnfe);
        } catch (ClassCastException cce) {
            throw new BuildException(className + " isn\'t the classname of "
                    + "a compiler adapter.", cce);
        } catch (Throwable t) {
            // for all other possibilities
            throw new BuildException("Compiler Adapter " + className
                    + " caused an interesting exception.", t);
        }
    }

}