No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?

最近在MINGW64控制台中使用 maven 命令打包时出现如下错误。通常在 eclipse 或 IDEA这样的集成开发工具中,只要将工程的JDK环境变量重新设置一下,重新执行一下maven 打包命令即可。

 1 [INFO] ------------------------------------------------------------------------
 2 [INFO] BUILD FAILURE
 3 [INFO] ------------------------------------------------------------------------
 4 [INFO] Total time: 1.628 s
 5 [INFO] Finished at: 2018-08-21T12:05:46+08:00
 6 [INFO] ------------------------------------------------------------------------
 7 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project xxx-framework: Compilation failure
 8 [ERROR] No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?
 9 [ERROR]
10 [ERROR] -> [Help 1]
11 org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project xxx-framework: Compilation failure
12 No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?
13 
14     at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:213)
15     at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:154)
16     at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:146)
17     at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
18     at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
19     at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
20     at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
21     at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
22     at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
23     at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
24     at org.apache.maven.cli.MavenCli.execute (MavenCli.java:956)
25     at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:290)
26     at org.apache.maven.cli.MavenCli.main (MavenCli.java:194)
27     at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
28     at sun.reflect.NativeMethodAccessorImpl.invoke (Unknown Source)
29     at sun.reflect.DelegatingMethodAccessorImpl.invoke (Unknown Source)
30     at java.lang.reflect.Method.invoke (Unknown Source)
31     at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:289)
32     at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:229)
33     at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:415)
34     at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:356)
35 Caused by: org.apache.maven.plugin.compiler.CompilationFailureException: Compilation failure
36 No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?
37 
38     at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute (AbstractCompilerMojo.java:1161)
39     at org.apache.maven.plugin.compiler.CompilerMojo.execute (CompilerMojo.java:168)
40     at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
41     at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:208)
42     at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:154)
43     at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:146)
44     at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
45     at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
46     at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
47     at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
48     at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
49     at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
50     at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
51     at org.apache.maven.cli.MavenCli.execute (MavenCli.java:956)
52     at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:290)
53     at org.apache.maven.cli.MavenCli.main (MavenCli.java:194)
54     at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
55     at sun.reflect.NativeMethodAccessorImpl.invoke (Unknown Source)
56     at sun.reflect.DelegatingMethodAccessorImpl.invoke (Unknown Source)
57     at java.lang.reflect.Method.invoke (Unknown Source)
58     at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:289)
59     at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:229)
60     at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:415)
61     at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:356)
62 [ERROR]
63 [ERROR]
64 [ERROR] For more information about the errors and possible solutions, please read the following articles:
65 [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
66 [ERROR]
67 [ERROR] After correcting the problems, you can resume the build with the command
[ERROR] mvn <goals> -rf :xxx-framework 

 

错误源头分析:  

  我试了一下,在IDEA中是可以正常执行maven打包命令。由于这种错误出现过很多次,但是却不知道其背后的原因,这次又碰到了,于是决定从源头上看看究竟是什么原因导致的。根据上面的异常提示信息,一路追踪下来,发现异常是从这个类(如下所示,该类位于plexus-compiler-javac-2.8.2.jar 之中)的方法抛出来的。

org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.compileInProcess(String[], CompilerConfiguration, String[])

很容易看出来是compiler等于null,导致出错。而compiler变量是由执行 getJavaCompiler 方法后赋值的。进入到这个方法(如下所示,该方法位于plexus-compiler-javac-2.8.2.jar 之中)里面去看看。

org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.getJavaCompiler(CompilerConfiguration)
 1     protected static JavaCompiler getJavaCompiler( CompilerConfiguration compilerConfiguration )
 2     {
 3         switch ( compilerConfiguration.getCompilerReuseStrategy() )
 4         {
 5             case AlwaysNew:
 6                 return ToolProvider.getSystemJavaCompiler();
 7             case ReuseCreated: //打断点跟踪会执行此处
 8                 JavaCompiler javaCompiler;
 9                 synchronized ( JAVA_COMPILERS )
10                 {
11                     if ( JAVA_COMPILERS.size() > 0 )
12                     {
13                         javaCompiler = JAVA_COMPILERS.get( 0 );
14                         JAVA_COMPILERS.remove( javaCompiler );
15                         return javaCompiler;
16                     }
17                 }
18                 javaCompiler = ToolProvider.getSystemJavaCompiler();
19                 return javaCompiler;
20             case ReuseSame:
21             default:
22                 return COMPILER;
23         }
24 
25     }
打断点跟踪了一下,会执行 ReuseCreated 分支。JAVA_COMPILERS 列表大小为空,执行  ToolProvider.getSystemJavaCompiler(),进入到这个方法中,发现这个方法查找某接口的实现类(如下所示),然后加载该实现类并实例化。
javax.tools.ToolProvider.getSystemJavaCompiler()

private static final String defaultJavaCompilerName= "com.sun.tools.javac.api.JavacTool";

跟踪到这儿,看到com.sun这个包我一时半会儿还没有反应过来,这个是JDK私有的包。既然了找不到实现类,那我就创建一个实现该接口的类,这样的话就不会报错了,然而当我把眼光停留到控制台那行红色错误提示信息上面,心想是不是应该使用 mvn -v 命令看一下,是不是加载的JDK路径不对导致的? 在 MINGW64 中执行 mvn -v 命令,控制台打印出来的信息如下所示:

1 $ mvn -v
2 Apache Maven 3.5.3 (3383c37e1f9e9b3bc3df5050c29c8aff9f295297; 2018-02-25T03:49:05+08:00)
3 Maven home: D:\prog\apache-maven-3.5.3
4 Java version: 1.8.0_161, vendor: Oracle Corporation
5 Java home: C:\Program Files\Java\jre
6 Default locale: zh_CN, platform encoding: GBK
7 OS name: "windows 7", version: "6.1", arch: "amd64", family: "windows"

看到控制台输出的Java home路径,跟我在环境中配置的JAVA_HOME路径不一样,奇怪了? 打开cmd, 在cmd命令行中执行 mvn -v 命令,控制台打印出来的信息如下所示:

1 C:\Users\hyt>mvn -v
2 Apache Maven 3.5.3 (3383c37e1f9e9b3bc3df5050c29c8aff9f295297; 2018-02-25T03:49:05+08:00)
3 Maven home: D:\prog\apache-maven-3.5.3\bin\..
4 Java version: 1.8.0_161, vendor: Oracle Corporation
5 Java home: C:\Program Files\Java\jdk1.8.0_161\jre
6 Default locale: zh_CN, platform encoding: GBK
7 OS name: "windows 7", version: "6.1", arch: "amd64", family: "windows"

对比之后,发现两者不一样,打开maven源码工程,看一下执行 mvn -v 命令的输出版本信息的方法,看一下究竟是从什么地方读取JDK的路径信息的。

org.apache.maven.cli.MavenCli#version

    private void version( CliRequest cliRequest )
    {
        if ( cliRequest.debug || cliRequest.commandLine.hasOption( CLIManager.SHOW_VERSION ) )
        {
            System.out.println( CLIReportingUtils.showVersion() );
        }
    }
org.apache.maven.cli.CLIReportingUtils#showVersion

    public static String showVersion()
    {
        final String ls = System.getProperty( "line.separator" );
        Properties properties = getBuildProperties();
        StringBuilder version = new StringBuilder( 256 );
        version.append( buffer().strong( createMavenVersionString( properties ) ) ).append( ls );
        version.append( reduce(
            properties.getProperty( "distributionShortName" ) + " home: " + System.getProperty( "maven.home",
                                                                                                "<unknown Maven "
                                                                                                    + "home>" ) ) )
            .append( ls );
        version.append( "Java version: " ).append(
            System.getProperty( "java.version", "<unknown Java version>" ) ).append( ", vendor: " ).append(
            System.getProperty( "java.vendor", "<unknown vendor>" ) ).append( ", runtime: " ).append(
            System.getProperty( "java.home", "<unknown runtime>" ) ).append( ls );
        version.append( "Default locale: " ).append( Locale.getDefault() ).append( ", platform encoding: " ).append(
            System.getProperty( "file.encoding", "<unknown encoding>" ) ).append( ls );
        version.append( "OS name: \"" ).append( Os.OS_NAME ).append( "\", version: \"" ).append( Os.OS_VERSION ).append(
            "\", arch: \"" ).append( Os.OS_ARCH ).append( "\", family: \"" ).append( Os.OS_FAMILY ).append( '\"' );
        return version.toString();
    }

  看到这儿我明白了,是在执行mvn命令的时候传入JDK路径不正确,我手动传入JDK路径来试试看能不能解决这个问题。我找到mvn.cmd文件,在该文件中(如下所示位置,使用notepad++编辑打开)设置JAVA_HOME路径,在 MINGW64 中执行 mvn install 依然提示错误信息,mvn -v 打印出的信息中 java home 路径依然是错误的。mvn -DJAVA_HOME=C:/Program Files/Java/jdk1.8.0_161/ install  采用这样的方式强制传入JAVA_HOME参数,导致maven根本无法识别 install 命令。 

  看来得研究一下 MINGW64 和 cmd 这两者为什么打印出来的JDK路径不一样,难不成 MINGW64 没有读取系统环境变量。 不过在此之前我要先尝试一下在 maven-compile-plugin 插件中增加<forceJavacCompilerUse>true</forceJavacCompilerUse> 配置项。因为前面代码提示 compiler 为空,是因为使用了JavaxToolsCompiler来编译源代码,我让maven直接使用javac命令来编译源代码,这样就不会提示找不到complier,从而compiler为null,这样做因该不会出错。

org.codehaus.plexus.compiler.javac.JavacCompiler.performCompile(CompilerConfiguration)

 //省略方法
if ( isJava16() && !config.isForceJavacCompilerUse() ) { // use fqcn to prevent loading of the class on 1.5 environment ! result =org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.compileInProcess( args, config, sourceFiles ); } else { result = compileInProcess( args, config ); }

在工程的 pom.xml 文件中为 maven-compile-plugin 插件中增加 <forceJavacCompilerUse>true</forceJavacCompilerUse> 配置项。

 1             <plugin>
 2                 <groupId>org.apache.maven.plugins</groupId>
 3                 <artifactId>maven-compiler-plugin</artifactId>
 4                 <!-- since 2.0 -->
 5                 <version>3.7.0</version>
 6                 <configuration>
 7                     <!-- use the Java 8 language features -->
 8                     <source>1.8</source>
 9                     <!-- want the compiled classes to be compatible with JVM 1.8 -->
10                     <target>1.8</target>
11                     <!-- The -encoding argument for the Java compiler. -->
12                     <encoding>UTF8</encoding>
13                     <forceJavacCompilerUse>true</forceJavacCompilerUse>
14                 </configuration>
15             </plugin>

在 MINGW64 中执行 mvn install 命令,错误依旧

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project xxx-framework: Fatal error compiling: tools.jar not found: C:\Program Files\Java\jre\..\lib\tools.jar -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

  没办法,回到设置 MINGW64 读取windows环境变量的路子上来,只有这样才能读取正确的JDK路径。可是在网上找了好长时间,都是说如何设置 MINGW64 的C++  gcc环境变量之类,不是自己想要。猛然脑海中想到3个字“注册表”。果然在“注册表”中找到与JDK相关的配置项。

HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment


 

问题的解决办法:

编辑注册表中相关的配置项,来解决这个问题。配置如下所示:

使用上面的配置之后,在 MINGW64 中执行 mvn install 命令之后,控制台提示报错。

$ mvn install
Error: could not open `C:\Program Files\Java\jdk1.8.0_161\lib\amd64\jvm.cfg'

我在这个目录下面去看了一下,果然没有这个文件。在这个路径 C:\Program Files\Java\jdk1.8.0_161\jre\lib\amd64 才有相关的配置,修改一下配置,如下所示:

 

 在 MINGW64 中执行mvn  install命令,控制台提示打包成功,mvn -v 输出的信息显示jdk路径也配置正确。


 

原因分析:

对 C:\Program Files\Java\jre 和 C:\Program Files\Java\jdk1.8.0_161\jre 这二者之间的区别没有弄清楚。开发的时候要指向JDK中的jre,因为要根据该jre的位置来做定位,加载JDK中的相关资源。比如上面maven要加载JDK中的com.sun私有包。关于这二者的区别可以在网上搜索,有关这方面的文章挺多的。 

 附CSDN上的某篇文章: java中的两个jre区别 https://blog.csdn.net/sanjiaozhen/article/details/45157565

posted @ 2018-08-21 16:35  来自非洲大草原的食人虎  阅读(32194)  评论(5编辑  收藏  举报