aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/compilers/CompilerAdapterFactory.java
blob: aeecb4a50ee09bf8352557dbf640cc4b70b83278 (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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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.types.Path;
import org.apache.tools.ant.util.ClasspathUtils;
import org.apache.tools.ant.util.JavaEnvUtils;

/**
 * Creates the necessary compiler adapter, given basic criteria.
 *
 * @since Ant 1.3
 */
public final 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.
     * @return the compiler adapter
     * @throws BuildException if the compiler type could not be resolved into
     * a compiler adapter.
     */
    public static CompilerAdapter getCompiler(String compilerType, Task task)
        throws BuildException {
        return getCompiler(compilerType, task, null);
    }

    /**
     * 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.
     * @param classpath the classpath to use when looking up an
     * adapter class
     * @return the compiler adapter
     * @throws BuildException if the compiler type could not be resolved into
     * a compiler adapter.
     * @since Ant 1.8.0
     */
    public static CompilerAdapter getCompiler(String compilerType, Task task,
                                              Path classpath)
        throws BuildException {
            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")) {
                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")
                || compilerType.equalsIgnoreCase("javac1.6")
                || compilerType.equalsIgnoreCase("javac1.7")
                || compilerType.equalsIgnoreCase("javac1.8")
                || compilerType.equalsIgnoreCase("javac1.9")) {
                // does the modern compiler exist?
                if (doesModernCompilerExist()) {
                    return new Javac13();
                } 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.\n"
                            + "It is currently set to \""
                            + JavaEnvUtils.getJavaHome()
                            + "\"");
                }
            }

            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,
                                    // Memory-Leak in line below
                                task.getProject().createClassLoader(classpath));
        }

    /**
     * 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 {
                ClassLoader cl = CompilerAdapterFactory.class.getClassLoader();
                if (cl != null) {
                    cl.loadClass(MODERN_COMPILER);
                    return true;
                }
            } catch (ClassNotFoundException cnfe2) {
                // Ignore Exception
            }
        }
        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.
     * @param loader the classloader to use
     * @throws BuildException This is the fit that is thrown if className
     * isn't an instance of CompilerAdapter.
     */
    private static CompilerAdapter resolveClassName(String className,
                                                    ClassLoader loader)
        throws BuildException {
        return (CompilerAdapter) ClasspathUtils.newInstance(className,
                loader != null ? loader :
                CompilerAdapterFactory.class.getClassLoader(),
                CompilerAdapter.class);
    }

}