zoukankan      html  css  js  c++  java
  • (ecj)Eclipse的Java编译器分析之一——ecj介绍

      Java是一个开放的平台,对于除发布编译器/解释器/基础类库之外,该语言的负责机构更多的是制定一系列标准,任何符合标准的厂商产品均可用于市场投放。甚至包括其编译器及解释器。

      (比如Hibernate提供了JPA实现;Tomcat实现了Java EE服务器标准,其Servlet容器通过了Java认证;各数据库或中间件厂商也根据JDBC接口开发驱动。说白了,Java基本就是都提供接口,然后让厂商开发实现,因此有时候我会骂,边骂边编码!)

      GCC有java编译器,可以看看。

      我们主要主要介绍Eclipse自己开发和使用的针对Java的编译器:(ecj) the Eclipse Compiler for Java。Eclipse没有使用JDK自带的编译器,而是自己开发的,ecj也通过了java的验证。

      除了Eclipse之外,Tomcat也用到了Ecj,用于动态编译jsp文件。我们安装Tomcat后可在lib文件夹下找到ecj:

      

      现在问题来了:怎么取得ecj源码呢?

      别急,我们从tomcat源码中查看一下:

      

      

      虽然我不熟ant,但我也能知道,Tomcat6.0.37中使用的ecj下载路径是:

      http://archive.eclipse.org/eclipse/downloads/drops4/R-4.2.2-201302041200/ecj-4.2.2.jar

      这个还是class文件,刚开始我也没辙,不过后来我灵机一动:在ecj后面加个src竟然成了!-_-

      http://archive.eclipse.org/eclipse/downloads/drops4/R-4.2.2-201302041200/ecjsrc-4.2.2.jar

      下面是我下载好后倒入项目文件后截图:

      

      

      这个文件报错,不过可以把他删除了看,我先没有删除,因为这个文件是ecj与ant的桥梁。从源码可以看出这个JDTCompilerAdapter是继承自ant的DefaultCompilerAdapter,用于ant的编译器适配器。个人感觉ecj从代码(技术)上并没有耦合任何一个调用者,这里的ant也只是一个适配器,你删除或者留着没有任何影响。Tomcat里也没有使用ant。

      我从这里主要是想看看高层怎么调用ecj来编译代码,我们看看关键代码:

      

     1 private static String compilerClass = "org.eclipse.jdt.internal.compiler.batch.Main"; //$NON-NLS-1$
     2 
     3 /**
     4      * Performs a compile using the JDT batch compiler
     5      * @throws BuildException if anything wrong happen during the compilation
     6      * @return boolean true if the compilation is ok, false otherwise
     7      */
     8     public boolean execute() throws BuildException {
     9         this.attributes.log(AntAdapterMessages.getString("ant.jdtadapter.info.usingJDTCompiler"), Project.MSG_VERBOSE); //$NON-NLS-1$
    10         Commandline cmd = setupJavacCommand();
    11 
    12         try {
    13             Class c = Class.forName(compilerClass);
    14             Constructor batchCompilerConstructor = 
    15                     c.getConstructor(new Class[] { 
    16                             PrintWriter.class, 
    17                             PrintWriter.class, 
    18                             Boolean.TYPE, 
    19                             Map.class});
    20             Object batchCompilerInstance = 
    21                     batchCompilerConstructor.newInstance(new Object[] {
    22                             new PrintWriter(System.out), 
    23                             new PrintWriter(System.err), 
    24                             Boolean.TRUE, 
    25                             this.customDefaultOptions});
    26             Method compile = 
    27                     c.getMethod("compile", new Class[] {String[].class}); //$NON-NLS-1$
    28             Object result = 
    29                     compile.invoke(batchCompilerInstance, new Object[] { 
    30                             cmd.getArguments()});
    31             final boolean resultValue = ((Boolean) result).booleanValue();
    32             if (!resultValue && this.logFileName != null) {
    33                 this.attributes.log(AntAdapterMessages.getString("ant.jdtadapter.error.compilationFailed", this.logFileName)); //$NON-NLS-1$
    34             }
    35             return resultValue;
    36         } catch (ClassNotFoundException cnfe) {
    37             throw new BuildException(AntAdapterMessages.getString("ant.jdtadapter.error.cannotFindJDTCompiler")); //$NON-NLS-1$
    38         } catch (Exception ex) {
    39             throw new BuildException(ex);
    40         }
    41     }

      我把代码换了下行,大家看13和26行,可以看出这里使用了

      org.eclipse.jdt.internal.compiler.batch.Main#compile(String[])方法来进行编译,我们可以稍微看看:

      从源码上来看1664是配置,1684可能是编译,不过我们先不细看。

      我们再看看Tomcat怎么使用ecj的,我们查看org.apache.jasper.compiler.JDTCompiler源码(我贴出了源码,不过有点长):

      

      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  * 
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  * 
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package org.apache.jasper.compiler;
     19 
     20 import java.io.BufferedOutputStream;
     21 import java.io.BufferedReader;
     22 import java.io.ByteArrayOutputStream;
     23 import java.io.File;
     24 import java.io.FileInputStream;
     25 import java.io.FileNotFoundException;
     26 import java.io.FileOutputStream;
     27 import java.io.IOException;
     28 import java.io.InputStream;
     29 import java.io.InputStreamReader;
     30 import java.io.Reader;
     31 import java.util.ArrayList;
     32 import java.util.HashMap;
     33 import java.util.Locale;
     34 import java.util.Map;
     35 import java.util.StringTokenizer;
     36 
     37 import org.apache.jasper.JasperException;
     38 import org.eclipse.jdt.core.compiler.IProblem;
     39 import org.eclipse.jdt.internal.compiler.ClassFile;
     40 import org.eclipse.jdt.internal.compiler.CompilationResult;
     41 import org.eclipse.jdt.internal.compiler.Compiler;
     42 import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
     43 import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
     44 import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
     45 import org.eclipse.jdt.internal.compiler.IProblemFactory;
     46 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
     47 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
     48 import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
     49 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
     50 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
     51 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
     52 
     53 /**
     54  * JDT class compiler. This compiler will load source dependencies from the
     55  * context classloader, reducing dramatically disk access during 
     56  * the compilation process.
     57  *
     58  * @author Cocoon2
     59  * @author Remy Maucherat
     60  */
     61 public class JDTCompiler extends org.apache.jasper.compiler.Compiler {
     62 
     63     
     64     /** 
     65      * Compile the servlet from .java file to .class file
     66      */
     67     protected void generateClass(String[] smap)
     68         throws FileNotFoundException, JasperException, Exception {
     69 
     70         long t1 = 0;
     71         if (log.isDebugEnabled()) {
     72             t1 = System.currentTimeMillis();
     73         }
     74         
     75         final String sourceFile = ctxt.getServletJavaFileName();
     76         final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
     77         String packageName = ctxt.getServletPackageName();
     78         final String targetClassName = 
     79             ((packageName.length() != 0) ? (packageName + ".") : "") 
     80                     + ctxt.getServletClassName();
     81         final ClassLoader classLoader = ctxt.getJspLoader();
     82         String[] fileNames = new String[] {sourceFile};
     83         String[] classNames = new String[] {targetClassName};
     84         final ArrayList problemList = new ArrayList();
     85         
     86         class CompilationUnit implements ICompilationUnit {
     87 
     88             String className;
     89             String sourceFile;
     90 
     91             CompilationUnit(String sourceFile, String className) {
     92                 this.className = className;
     93                 this.sourceFile = sourceFile;
     94             }
     95 
     96             public char[] getFileName() {
     97                 return sourceFile.toCharArray();
     98             }
     99             
    100             public char[] getContents() {
    101                 char[] result = null;
    102                 FileInputStream is = null;
    103                 try {
    104                     is = new FileInputStream(sourceFile);
    105                     Reader reader = 
    106                         new BufferedReader(new InputStreamReader(is, ctxt.getOptions().getJavaEncoding()));
    107                     if (reader != null) {
    108                         char[] chars = new char[8192];
    109                         StringBuffer buf = new StringBuffer();
    110                         int count;
    111                         while ((count = reader.read(chars, 0, 
    112                                                     chars.length)) > 0) {
    113                             buf.append(chars, 0, count);
    114                         }
    115                         result = new char[buf.length()];
    116                         buf.getChars(0, result.length, result, 0);
    117                     }
    118                 } catch (IOException e) {
    119                     log.error("Compilation error", e);
    120                 } finally {
    121                     if (is != null) {
    122                         try {
    123                             is.close();
    124                         } catch (IOException exc) {
    125                             // Ignore
    126                         }
    127                     }
    128                 }
    129                 return result;
    130             }
    131             
    132             public char[] getMainTypeName() {
    133                 int dot = className.lastIndexOf('.');
    134                 if (dot > 0) {
    135                     return className.substring(dot + 1).toCharArray();
    136                 }
    137                 return className.toCharArray();
    138             }
    139             
    140             public char[][] getPackageName() {
    141                 StringTokenizer izer = 
    142                     new StringTokenizer(className, ".");
    143                 char[][] result = new char[izer.countTokens()-1][];
    144                 for (int i = 0; i < result.length; i++) {
    145                     String tok = izer.nextToken();
    146                     result[i] = tok.toCharArray();
    147                 }
    148                 return result;
    149             }
    150 
    151             public boolean ignoreOptionalProblems() {
    152                 return false;
    153             }
    154         }
    155 
    156         final INameEnvironment env = new INameEnvironment() {
    157 
    158                 public NameEnvironmentAnswer 
    159                     findType(char[][] compoundTypeName) {
    160                     String result = "";
    161                     String sep = "";
    162                     for (int i = 0; i < compoundTypeName.length; i++) {
    163                         result += sep;
    164                         result += new String(compoundTypeName[i]);
    165                         sep = ".";
    166                     }
    167                     return findType(result);
    168                 }
    169 
    170                 public NameEnvironmentAnswer 
    171                     findType(char[] typeName, 
    172                              char[][] packageName) {
    173                         String result = "";
    174                         String sep = "";
    175                         for (int i = 0; i < packageName.length; i++) {
    176                             result += sep;
    177                             result += new String(packageName[i]);
    178                             sep = ".";
    179                         }
    180                         result += sep;
    181                         result += new String(typeName);
    182                         return findType(result);
    183                 }
    184                 
    185                 private NameEnvironmentAnswer findType(String className) {
    186 
    187                     InputStream is = null;
    188                     try {
    189                         if (className.equals(targetClassName)) {
    190                             ICompilationUnit compilationUnit = 
    191                                 new CompilationUnit(sourceFile, className);
    192                             return 
    193                                 new NameEnvironmentAnswer(compilationUnit, null);
    194                         }
    195                         String resourceName = 
    196                             className.replace('.', '/') + ".class";
    197                         is = classLoader.getResourceAsStream(resourceName);
    198                         if (is != null) {
    199                             byte[] classBytes;
    200                             byte[] buf = new byte[8192];
    201                             ByteArrayOutputStream baos = 
    202                                 new ByteArrayOutputStream(buf.length);
    203                             int count;
    204                             while ((count = is.read(buf, 0, buf.length)) > 0) {
    205                                 baos.write(buf, 0, count);
    206                             }
    207                             baos.flush();
    208                             classBytes = baos.toByteArray();
    209                             char[] fileName = className.toCharArray();
    210                             ClassFileReader classFileReader = 
    211                                 new ClassFileReader(classBytes, fileName, 
    212                                                     true);
    213                             return 
    214                                 new NameEnvironmentAnswer(classFileReader, null);
    215                         }
    216                     } catch (IOException exc) {
    217                         log.error("Compilation error", exc);
    218                     } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException exc) {
    219                         log.error("Compilation error", exc);
    220                     } finally {
    221                         if (is != null) {
    222                             try {
    223                                 is.close();
    224                             } catch (IOException exc) {
    225                                 // Ignore
    226                             }
    227                         }
    228                     }
    229                     return null;
    230                 }
    231 
    232                 private boolean isPackage(String result) {
    233                     if (result.equals(targetClassName)) {
    234                         return false;
    235                     }
    236                     String resourceName = result.replace('.', '/') + ".class";
    237                     InputStream is = 
    238                         classLoader.getResourceAsStream(resourceName);
    239                     return is == null;
    240                 }
    241 
    242                 public boolean isPackage(char[][] parentPackageName, 
    243                                          char[] packageName) {
    244                     String result = "";
    245                     String sep = "";
    246                     if (parentPackageName != null) {
    247                         for (int i = 0; i < parentPackageName.length; i++) {
    248                             result += sep;
    249                             String str = new String(parentPackageName[i]);
    250                             result += str;
    251                             sep = ".";
    252                         }
    253                     }
    254                     String str = new String(packageName);
    255                     if (Character.isUpperCase(str.charAt(0))) {
    256                         if (!isPackage(result)) {
    257                             return false;
    258                         }
    259                     }
    260                     result += sep;
    261                     result += str;
    262                     return isPackage(result);
    263                 }
    264 
    265                 public void cleanup() {
    266                 }
    267 
    268             };
    269 
    270         final IErrorHandlingPolicy policy = 
    271             DefaultErrorHandlingPolicies.proceedWithAllProblems();
    272 
    273         final Map settings = new HashMap();
    274         settings.put(CompilerOptions.OPTION_LineNumberAttribute,
    275                      CompilerOptions.GENERATE);
    276         settings.put(CompilerOptions.OPTION_SourceFileAttribute,
    277                      CompilerOptions.GENERATE);
    278         settings.put(CompilerOptions.OPTION_ReportDeprecation,
    279                      CompilerOptions.IGNORE);
    280         if (ctxt.getOptions().getJavaEncoding() != null) {
    281             settings.put(CompilerOptions.OPTION_Encoding,
    282                     ctxt.getOptions().getJavaEncoding());
    283         }
    284         if (ctxt.getOptions().getClassDebugInfo()) {
    285             settings.put(CompilerOptions.OPTION_LocalVariableAttribute,
    286                          CompilerOptions.GENERATE);
    287         }
    288 
    289         // Source JVM
    290         if(ctxt.getOptions().getCompilerSourceVM() != null) {
    291             String opt = ctxt.getOptions().getCompilerSourceVM();
    292             if(opt.equals("1.1")) {
    293                 settings.put(CompilerOptions.OPTION_Source,
    294                              CompilerOptions.VERSION_1_1);
    295             } else if(opt.equals("1.2")) {
    296                 settings.put(CompilerOptions.OPTION_Source,
    297                              CompilerOptions.VERSION_1_2);
    298             } else if(opt.equals("1.3")) { 
    299                 settings.put(CompilerOptions.OPTION_Source,
    300                              CompilerOptions.VERSION_1_3);
    301             } else if(opt.equals("1.4")) {
    302                 settings.put(CompilerOptions.OPTION_Source,
    303                              CompilerOptions.VERSION_1_4);
    304             } else if(opt.equals("1.5")) {
    305                 settings.put(CompilerOptions.OPTION_Source,
    306                              CompilerOptions.VERSION_1_5);
    307             } else if(opt.equals("1.6")) {
    308                 settings.put(CompilerOptions.OPTION_Source,
    309                              CompilerOptions.VERSION_1_6);
    310             } else if(opt.equals("1.7")) {
    311                 settings.put(CompilerOptions.OPTION_Source,
    312                              CompilerOptions.VERSION_1_7);
    313             } else {
    314                 log.warn("Unknown source VM " + opt + " ignored.");
    315                 settings.put(CompilerOptions.OPTION_Source,
    316                         CompilerOptions.VERSION_1_5);
    317             }
    318         } else {
    319             // Default to 1.5
    320             settings.put(CompilerOptions.OPTION_Source,
    321                     CompilerOptions.VERSION_1_5);
    322         }
    323         
    324         // Target JVM
    325         if(ctxt.getOptions().getCompilerTargetVM() != null) {
    326             String opt = ctxt.getOptions().getCompilerTargetVM();
    327             if(opt.equals("1.1")) {
    328                 settings.put(CompilerOptions.OPTION_TargetPlatform,
    329                              CompilerOptions.VERSION_1_1);
    330             } else if(opt.equals("1.2")) {
    331                 settings.put(CompilerOptions.OPTION_TargetPlatform,
    332                              CompilerOptions.VERSION_1_2);
    333             } else if(opt.equals("1.3")) { 
    334                 settings.put(CompilerOptions.OPTION_TargetPlatform,
    335                              CompilerOptions.VERSION_1_3);
    336             } else if(opt.equals("1.4")) {
    337                 settings.put(CompilerOptions.OPTION_TargetPlatform,
    338                              CompilerOptions.VERSION_1_4);
    339             } else if(opt.equals("1.5")) {
    340                 settings.put(CompilerOptions.OPTION_TargetPlatform,
    341                              CompilerOptions.VERSION_1_5);
    342                 settings.put(CompilerOptions.OPTION_Compliance,
    343                         CompilerOptions.VERSION_1_5);
    344             } else if(opt.equals("1.6")) {
    345                 settings.put(CompilerOptions.OPTION_TargetPlatform,
    346                              CompilerOptions.VERSION_1_6);
    347                 settings.put(CompilerOptions.OPTION_Compliance,
    348                         CompilerOptions.VERSION_1_6);
    349             } else if(opt.equals("1.7")) {
    350                 settings.put(CompilerOptions.OPTION_TargetPlatform,
    351                              CompilerOptions.VERSION_1_7);
    352                 settings.put(CompilerOptions.OPTION_Compliance,
    353                         CompilerOptions.VERSION_1_7);
    354             } else {
    355                 log.warn("Unknown target VM " + opt + " ignored.");
    356                 settings.put(CompilerOptions.OPTION_TargetPlatform,
    357                         CompilerOptions.VERSION_1_5);
    358             }
    359         } else {
    360             // Default to 1.5
    361             settings.put(CompilerOptions.OPTION_TargetPlatform,
    362                     CompilerOptions.VERSION_1_5);
    363             settings.put(CompilerOptions.OPTION_Compliance,
    364                     CompilerOptions.VERSION_1_5);
    365         }
    366 
    367         final IProblemFactory problemFactory = 
    368             new DefaultProblemFactory(Locale.getDefault());
    369         
    370         final ICompilerRequestor requestor = new ICompilerRequestor() {
    371                 public void acceptResult(CompilationResult result) {
    372                     try {
    373                         if (result.hasProblems()) {
    374                             IProblem[] problems = result.getProblems();
    375                             for (int i = 0; i < problems.length; i++) {
    376                                 IProblem problem = problems[i];
    377                                 if (problem.isError()) {
    378                                     String name = 
    379                                         new String(problems[i].getOriginatingFileName());
    380                                     try {
    381                                         problemList.add(ErrorDispatcher.createJavacError
    382                                                 (name, pageNodes, new StringBuffer(problem.getMessage()), 
    383                                                         problem.getSourceLineNumber(), ctxt));
    384                                     } catch (JasperException e) {
    385                                         log.error("Error visiting node", e);
    386                                     }
    387                                 }
    388                             }
    389                         }
    390                         if (problemList.isEmpty()) {
    391                             ClassFile[] classFiles = result.getClassFiles();
    392                             for (int i = 0; i < classFiles.length; i++) {
    393                                 ClassFile classFile = classFiles[i];
    394                                 char[][] compoundName = 
    395                                     classFile.getCompoundName();
    396                                 String className = "";
    397                                 String sep = "";
    398                                 for (int j = 0; 
    399                                      j < compoundName.length; j++) {
    400                                     className += sep;
    401                                     className += new String(compoundName[j]);
    402                                     sep = ".";
    403                                 }
    404                                 byte[] bytes = classFile.getBytes();
    405                                 String outFile = outputDir + "/" + 
    406                                     className.replace('.', '/') + ".class";
    407                                 FileOutputStream fout = 
    408                                     new FileOutputStream(outFile);
    409                                 BufferedOutputStream bos = 
    410                                     new BufferedOutputStream(fout);
    411                                 bos.write(bytes);
    412                                 bos.close();
    413                             }
    414                         }
    415                     } catch (IOException exc) {
    416                         log.error("Compilation error", exc);
    417                     }
    418                 }
    419             };
    420 
    421         ICompilationUnit[] compilationUnits = 
    422             new ICompilationUnit[classNames.length];
    423         for (int i = 0; i < compilationUnits.length; i++) {
    424             String className = classNames[i];
    425             compilationUnits[i] = new CompilationUnit(fileNames[i], className);
    426         }
    427         Compiler compiler = new Compiler(env,
    428                                          policy,
    429                                          settings,
    430                                          requestor,
    431                                          problemFactory,
    432                                          true);
    433         compiler.compile(compilationUnits);
    434 
    435         if (!ctxt.keepGenerated()) {
    436             File javaFile = new File(ctxt.getServletJavaFileName());
    437             javaFile.delete();
    438         }
    439     
    440         if (!problemList.isEmpty()) {
    441             JavacErrorDetail[] jeds = 
    442                 (JavacErrorDetail[]) problemList.toArray(new JavacErrorDetail[0]);
    443             errDispatcher.javacError(jeds);
    444         }
    445         
    446         if( log.isDebugEnabled() ) {
    447             long t2=System.currentTimeMillis();
    448             log.debug("Compiled " + ctxt.getServletJavaFileName() + " "
    449                       + (t2-t1) + "ms");
    450         }
    451 
    452         if (ctxt.isPrototypeMode()) {
    453             return;
    454         }
    455 
    456         // JSR45 Support
    457         if (! options.isSmapSuppressed()) {
    458             SmapUtil.installSmap(smap);
    459         }
    460         
    461     }
    462     
    463     
    464 }
    TomcatAdapter

      

      从427可以知道,Tomcat使用了org.eclipse.jdt.internal.compiler.Compiler#compile(ICompilationUnit[])

      当然,在这之前使用了很多代码来进行配置。

      第一篇文章就到这里。

     欢迎您移步我们的交流群,无聊的时候大家一起打发时间:Programmer Union

     或者通过QQ与我联系:点击这里给我发消息

     (最后编辑时间2014-01-18 13:59:01)

  • 相关阅读:
    网易在帮助我们泄漏密码吗?
    ADC转换参数——INL_DNL
    高速ADC的关键指标:量化误差、offset/gain error、DNL、INL、ENOB、分辨率、RMS、SFDR、THD、SINAD、dBFS、TWOTONE IMD
    Altium Designer如何批量修改名称,数值,封装,NET颜色
    MAC和PHY的区别
    以太网,IP,TCP,UDP数据包分析
    《西安JAVA培训教学视频西安云工厂旺旺老师》更新struts1.SQLServer.设计模式.JavaScript.JavaWeb
    在DOS命令下写一个简单的HelloWorld程序
    你想遇到什么样的人,你先要成为什么样的人
    一些重要的shell命令
  • 原文地址:https://www.cnblogs.com/Johness/p/3525032.html
Copyright © 2011-2022 走看看