Windows子系统无法识别JAVA_HOME环境变量

30

我试图让WSL识别我在Windows安装的环境变量JAVA_HOME。我附上了我的bashrc中的内容,以及我在Windows环境变量中的内容,还有从cmd和bash中输出的结果。

JAVA_HOME Env. Var.

<code>enter image description here</code>

这是我bashrc文件的结尾内容:

export JAVA_HOME="/mnt/d/Program Files/Java/jdk-11.0.1"
export PATH="/mnt/d/Program Files/Java/jdk-11.0.1/bin:$PATH"

CMD输入/输出:

C:\Users\jaall>javac --version
javac 11.0.1

BASH输入/输出:

myubuntu_name@DESKTOP-LUK3BII:~$ javac --version

Command 'javac' not found, but can be installed with:

sudo apt install default-jdk
sudo apt install openjdk-11-jdk-headless
sudo apt install ecj
sudo apt install openjdk-8-jdk-headless

我已经卡在这个问题上有一段时间了,无法解决并且在网上也找不到可行的解决方案。谢谢!


4
使用 javac.exe 命令。建议使用 WSLENV 环境变量。链接:https://learn.microsoft.com/en-us/windows/wsl/interop - Biswapriyo
4个回答

34

如Biswapriyo所建议的,您应该使用WSLENV。

  1. 打开PowerShell。然后将JAVA_HOME设置为Java安装路径。

  2. 在您的情况下,运行setx JAVA_HOME "D:\Program Files\Java\jdk-11.0.1"

您应该会看到一个信息,内容是“SUCCESS: Specified value was saved”。

  1. 然后运行setx WSLENV "JAVA_HOME/p"

您应该再次看到成功的消息。

  1. 在您的WSL bash提示符中键入'env'。

此时,您应该能正确地设置JAVA_HOME

注意:如果步骤2不起作用,则可能需要更改JAVA_HOME的路径,以包括\bin文件夹。


2
在这里解释了WSLENV: https://blogs.msdn.microsoft.com/commandline/2017/12/22/share-environment-vars-between-wsl-and-windows/ - Leslie N
5
这设置了变量,但保留了空格,这给我带来了问题。 - Matt
5
我收到了这个错误信息: “Error: JAVA_HOME is not defined correctly. We cannot execute /mnt/c/Program Files/Java/jdk-11.0.7/bin/java" 但是在 Windows 10 中,JAVA_HOME 已正确设置并遵循您的步骤,但我仍然遇到了此错误。 - Panagiss
谢谢您在这里的回答。我想知道您是否有比我在这里做的更优雅的方法来修复WSL中的.env文件?https://stackoverflow.com/a/62836810/470749 谢谢! - Ryan
1
嘿,正如@Panagiss所说,在路径的“Program Files”部分中的空格使得在wsl上该路径无效...有什么解决方法可以在运行setx时避免这些空格吗? - fablexis
@fablexis 这个可能有效:setx JAVA_HOME "D:\Progra~1\Java\jdk-11.0.1"。@Ryan,抱歉,我不知道。 - Mbuotidem Isaac

17

我原本在Windows中安装了Maven,但尝试在WSL2中运行Maven并尝试了所有以前的解决方案,但无论我设置JAVA_HOME和PATH为什么,始终会得到以下提示:

$ mvn -v
The JAVA_HOME environment variable is not defined correctly
This environment variable is needed to run this program
NB: JAVA_HOME should point to a JDK not a JRE

问题在于我试图在WSL2 Linux内核中使用Windows版本的JDK。为解决此问题,我最终不得不在WSL中安装Linux版本的JDK(版本11),步骤如下:
$ sudo apt update
$ sudo apt install openjdk-11-jdk
$ sudo update-alternatives --config java
There is only one alternative in link group java (providing /usr/bin/java): /usr/lib/jvm/java-11-openjdk-amd64/bin/java
Nothing to configure.

接下来请使用JDK的路径来创建JAVA_HOME,并在.profile文件中添加以下内容来更新PATH:

export PATH="/usr/lib/jvm/java-11-openjdk-amd64/bin/java:$PATH"
export JAVA_HOME="/usr/lib/jvm/java-11-openjdk-amd64"

现在关闭并重新打开WSL2,然后再试一遍:
$ mvn -v
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 11.0.13, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: en, platform encoding: UTF-8
OS name: "linux", version: "5.10.16.3-microsoft-standard-wsl2", arch: "amd64", family: "unix"

1
谢谢。我错过的一个重要点需要注意的是,给JAVA_HOME的路径不能包含尾随的/bin/java(就像许多网站上说的那样),而应该指向基本目录,如答案中所述。 - Daya

11
在WSL中,你必须使用javac.exe,因为它是一个Windows二进制文件。仅仅输入javac是不起作用的,即使路径设置正确。如果这样还不起作用,尝试在JAVA_HOME变量的末尾添加../bin。
在WSL中使用Windows二进制文件和环境变量
有一种更简单的方法可以使Windows和WSL使用相同的JavaSDK二进制文件,你只需要先设置一些东西。最重要的是,如果你在Windows上安装了JavaSDK,你不需要安装Linux二进制文件。
检查WSL权限和目录链接(可选,但建议)
在WSL中,列出PC上的符号链接:
ls -l /mnt

如果任何驱动器的所有者是root,请在/mnt/c/Users/<UserName>中进行WSL开发工作。
个人而言,我会在Windows中创建一个开发目录,并在WSL中添加一个符号链接到该目录。
ln -s /mnt/d/dev/environment/ ~/dev

cd dev现在将您带到您的开发目录。

确保Windows上的Java工作正常

从任何目录打开PowerShell/cmd.exe并输入:java --version

您应该会得到一个JRE信息列表:

openjdk 11.0.4 2019-07-16 LTS
OpenJDK Runtime Environment Corretto-11.0.4.11.1 (build 11.0.4+11-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.4.11.1 (build 11.0.4+11-LTS, mixed mode)

你的版本可能不同,重要的是系统知道在哪里找到Java。如果你遇到错误,请确保你的Windows环境变量设置正确:
- JAVA_HOME作为环境变量 - JAVA_HOME/bin作为路径变量
在WSL中设置变量
最好的地方是将下面的代码放在你的.bashrc文件中,但如果你有一个./bash_profile或/etc/profile的结构设置,你也可以把它放在那里。
# Shared environment variables
# Use 'java.exe <args>' to utilize Windows Java binaries from within WSL.
export JAVA_HOME=/mnt/d/Java/jdk11.0.4_10

顺便说一下,我们也加上Maven吧。
export MAVEN_HOME=/mnt/d/software/apache-maven-3.6.2

我在我的第二个硬盘上设置了我的WSL、Java和所有其他开发工具,这个硬盘不是系统驱动器,请确保您的位置与Windows中的JAVA_HOME路径匹配。
例如,如果在Windows中,Java位于:C:\Java\jdk8.0 相应的WSL挂载点是:/mnt/c/Java/jdk8.0
执行
重要提示:在WSL中使用java.exe 而不是java 假设您刚刚编写了CompareTwoStrings.class,并希望使用Windows的二进制文件进行编译和运行。您可以从Windows shell或WSL中执行。
Windows PowerShell/cmd:
javac GetStringLength.java
java GetStringLength

WSL:

javac.exe GetStringLength.java
java.exe GetStringLength

在WSL中使用java <args>会导致Command 'java' not found错误。这是因为在WSL中运行Windows二进制文件需要使用.exe扩展名作为命令。此外,请确保您的导出语句末尾没有任何空格或分号,因为这会导致运行依赖于Java的任何内容时出错。

简单性

我们不想在WSL中安装第二份专门针对WSL的Java副本并浪费宝贵的磁盘空间,所以我们将从WSL shell调用Windows二进制文件。这是WSL的一个巨大优势,特别是WSL1,它可以(几乎)无缝地与Windows文件系统交互。

为了保持Windows和WSL之间的命令一致,您可以在.bashrc文件中添加一个别名,其中java = java.exejavac = javac.exe

注意:为了运行程序,它必须是一个Path变量,或者从包含它的文件夹中运行。

希望这对你来说像对我一样容易。只需记住根据你运行的操作系统二进制文件使用正确的命令。我花了大约10分钟来设置它,它对于交叉编译和使用的便利性真是救命稻草。

我按照你的方法操作了,一切都正常。但是当Java放在mnt中时,IntelliJ无法识别它。你能否请检查一下?https://stackoverflow.com/questions/71178507/executing-graal-vm-in-wsl-with-intellij - ahrooran
嗯,你没有详细说明如何实际让"Maven"工作。我按照你说的做了所有的事情,甚至在我的.bashrc中使用了alias java=java.exealias javac=javac.exe,以使它更适合Linux。但是仍然在输入mvn时显示:JAVA_HOME环境变量定义不正确,需要该环境变量才能运行此程序。 - undefined
1
@AshkanRanjbar 别名的选择很明智!对于Maven,按照设置Java/JRE的步骤进行操作。在两个环境中导出路径变量,例如MAVEN_HOME。确保设置了mvn的别名,或者如果你使用的是WSL中的Windows二进制文件,则使用mvn.exe。还要确保JAVA_HOME变量中没有尾部的反斜杠或分号。 - undefined
1
终于成功了,事实证明,将MAVEN_HOMEJAVA_HOME本身(在我的情况下是/mnt/c/Program\ Files/Maven/apache-maven-3.9.4/bin/mnt/c/Program\ Files/Java/jdk-21/bin)添加到环境变量路径中是一个关键步骤。 - undefined
@AshkanRanjbar 太棒了,很高兴它起作用了。我已经更新了我的答案,加入了 MAVEN_HOME - undefined

5

由于我以前从未能轻松地在两个系统之间共享变量,因此我创建了一个简单的bash函数,可以轻松获取(并在需要时定义)任何Windows环境变量。

它还会处理路径,使其从Win32转换为类Unix的路径表示方式。

我将其添加到/etc/bash.bashrc中:

winenv()
{
  if [ "$#" == "0" ] || [ "$1" == "--help" ]
  then
    echo $'\n'Usage:
    echo $'\t'winenv [-d] WINDOWS_ENVIRONEMENT_VARIABLE_NAME
    echo $'\t'-d: Defines environment variable in current shell
    echo $'\t    Note that paths will be translated into un*x-like\n'
    return
  fi
  local IFS='$\n'
  local PATH_TO_TRANSLATE=$1
  [ "$1" == "-d" ] && PATH_TO_TRANSLATE=$2
  local VAR=$(cmd.exe /c echo %${PATH_TO_TRANSLATE}% | tr -d '\r')
  local NEW=$(wslpath -u "${VAR}" 2>/dev/null || echo ${VAR})
  echo "${PATH_TO_TRANSLATE} = ${VAR} -> ${NEW}"
  [ "$1" == "-d" ] && export "${PATH_TO_TRANSLATE}=${NEW}"
}

要显示环境变量只需调用winenv PROGRAMFILES(例如)
如果要导出环境变量,只需在变量名之前加上 -d 参数,如:winenv -d WINDIR


1
如果你需要频繁地进行交叉编译或者在WSL中执行任务并且需要在WSL和Windows之间切换,那么这个脚本非常有用。感谢您的分享! - jon.bray.eth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接