idea調用ecj方法
因爲工作項目中同事用的編譯器是eclipse,想移植用idea,發現項目中很多文件包含有UTF8格式的BOM字符,如果更改文件格式也可以解決,想到idea調用外部ecj.jar來進行編譯,如果能在編譯讀取文件時判斷一下讀取的字符,去掉包含的特殊bom字符,就能從根源上解決這個問題了,參照網上之前的修改ecj.jar裏Utils類裏的一個讀取方法,試了一下沒有效果,用舊版17年的idea是可以使用的,可能是idea後面更改了調用的方式,2019.3版本聽說性能有很大提升,所以決定查找一下idea是如何調用ecj的方法來進行編譯的。
-
查看github上,有idea的社區版源碼,先clone下來;
-
有4個多G的文件,克隆下來之後,導入idea,直接open根目錄;堆內存加到1.5G,索引20分鐘超時,生成了部分索引可以用來查找
-
有很多報錯,不過沒事,目的不是啓動它,主要找編譯時調用ecj的方法
-
查找關鍵字終於在JavaBuilder找到了構建項目的方法
public ExitCode build(@NotNull CompileContext context, @NotNull ModuleChunk chunk, @NotNull DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder, @NotNull OutputConsumer outputConsumer) throws ProjectBuildException, IOException { JavaCompilingTool compilingTool = COMPILING_TOOL.get(context); if (!IS_ENABLED.get(context, Boolean.TRUE) || compilingTool == null) { return ExitCode.NOTHING_DONE; } // 用於構建項目的方法 return doBuild(context, chunk, dirtyFilesHolder, outputConsumer, compilingTool); }
-
在doBuild方法裏,從變量裏的Map獲得編譯所需要的編譯器(ecj使用的是JavaCompilingTool的子類EclipseCompilerTool),還有對java版本的校驗,是否使用javac進行編譯;
搭建ecj的運行環境
- 去eclipse官網找到對應的ecj版本源碼,這裏用的是ecj-4.10.jar;需要同時下載這個版本的sdk,org.eclipse.jdt-4.10
2. 使用idea打開,下載需要依賴的jar然後添加進去,這裏需要下載ant的jar包;
-
這個版本的ecj,使用了一些java11的api,使用java8無法編譯,切換爲java11;
-
在代碼裏找有沒有可執行的Main方法,看項目還有沒有錯誤,執行,控制檯輸出
Eclipse Compiler for Java(TM) bundle_qualifier, bundle_version Copyright IBM Corp 2000, 2015. All rights reserved. Usage: <options> <source files | directories> If directories are specified, then their source contents are compiled. Possible options are listed below. Options enabled by default are prefixed with '+'. Classpath options: -cp -classpath <directories and ZIP archives separated by ;> specify location for application classes and sources. Each directory or file can specify access rules for types between '[' and ']' (e.g. [-X] to forbid access to type X, [~X] to discourage access to type X, [+p/X;-p/*] to forbid access to all types in package p but allow access to p/X) .... 省略掉,意思就是調用這個方法,需要跟的一些args的解釋 VMOption跟java文件夾路徑,會對文件夾裏的java文件進行編譯
-
查看org.eclipse.jdt.internal.compiler.tool.EclipseCompiler#getTask方法,如何調用,然後就能debug,查看調用的方法了
-
調用call之後,實際上是去調用EclipseCompilerImpl的call方法了
-
最後發現,getTask裏的代碼,讀取java文件確實用到了Util#getInputStreamAsCharArray,對Util的兩個讀取文件方法都做了bom移除處理。
-
執行ecj的Main方法,args跟一個java文件夾的路徑,會對文件夾的java文件進行編譯,自己創建一個bom文件,發現可以處理,重新打包,然後idea配置compile爲eclipse,關聯重新打包的ecj-4.10.jar,還是不能處理,GG。
卡了好一陣子,還是想用新版的,應該是調用了其他方法,重新換一個地方找調用的方法,先導入默認的ecj包,不處理,查看它打印錯誤日誌的方法,
debug找到另一個讀取內容的地方(org/eclipse/jdt/internal/compiler/parser/Parser.java),在前面處理一下bom字符
重新編譯,替換文件,在2019.3.1是可以處理bom的,設置編譯方式爲eclipse,關聯ecj的jar包,不要用默認的(替換掉默認的也可以)
最後一個問題
如果整體項目使用UTF-8編譯(setting->encoding裏設置),有一些GBK裏的字符無法識別,
如果整體項目使用GBK編譯,報”諾縫ublic“,debug發現是文件是UTF-8 bom類型的文件,當做GBK文件來處理,直接按char讀的,所以就讀成了這個不識別的字,在parse.java裏面,再處理一下這兩個字符設置爲空字符和p字符就好了;
Util.java裏的讀取字節流默認是處理了bom字符的,但是由於項目設置,這個encoding到這裏的時候可能是個空選項,反正就是最後把所有可能遇到的問題都處理一下,項目文件分支比較多,編碼雜亂,別人用eclipse是可以正常運行的,原則上就不改變文件默認的東西,往已有的上面適配就好了
// Do not keep first character for UTF-8 BOM encoding
int start = 0;
if (totalRead > 0 && UTF_8.equals(encoding)) {
if (contents[0] == 0xFEFF) { // if BOM char then skip
totalRead--;
start = 1;
}
}
ecj.jar資源地址://download.csdn.net/download/qq_23747281/12077645