(Java)PATH、JAVA_HOME、CLASSPATHとは
Javaプログラミングを実施する際によく見かける用語について、そこまで難しい概念ではないが、整理のため記事にする。(見つけ次第追記していく)
PATH
これはJavaに限らずだが、Javaなどを自分のパソコンにインストールした際に「パスを通す」というワードを見かけると思う。その「パス」のこと。
大雑把に「パスを通す」とは何をしているかというと、ターミナルやコマンドプロンプト上でOSに実行させたいコマンドを登録するイメージ。
詳細
まず、以下のコマンドをターミナルで入力してみる。
echo $PATH
私の環境では以下でした(多分荒らしまくっている)。
bobby% echo $PATH
/Library/Java/JavaVirtualMachines/openjdk.jdk/Contents/Home/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin
このPATHとは環境変数の一種である。
詳細は省略するが、環境変数はOSが何かしらの機能を実行する際に参照する変数のことである。
そして、PATHという環境変数は、OSがターミナルに入力されたコマンドを実行する際に、実態として動く実行可能ファイルが格納されているディレクトリのパスが記載されている。
内部的に、OSはターミナルからコマンドを受け取った際に、コマンドのファイル(実行可能ファイル)の絶対パスを、PATHで指定されたディレクトリ群から探し出して実行している。
そのため、例えばjavaをインストールして、パスを通さないまま以下のコマンドを実行しても、エラーとなる。
javac Test.java #コマンドが見つからないとエラーになる
そのため、新規にアプリケーションをインストールした際は(必要な場合は)パスを通して、OSにコマンドを実行可能にさせるのである。
ちなみに、馴染み深いlsコマンドもPATHに登録されている。
bobby% type ls #typeコマンドでそのコマンドがどこにあるかわかる
ls is /bin/ls
bobby% more /bin/ls #lsの中身を見ようとしている(バイナリなので割愛)
"/bin/ls" may be a binary file. See it anyway?
JAVA_HOME
これも環境変数の一種で、インストールされているJava(JDK)のルートディレクトリを指し示すために使用される。
PATHで述べた通りjavaコマンドを実行するには環境変数PATHを設定すれば良いため、個人的に必要性が不明な環境変数だった。
しかし、Gradleや開発ツールで当変数を参照するとのこと。
自分が明示的に使用したことがないため曖昧にはなってしまうが、java自体が使う変数というよりは、その他ツールがJavaを使用するために参照する変数と理解。
CLASSPATH
Gradleを学ぶ際によく使われる依存関係とはでも説明したが、JavaのコンパイラやJVMは、指定されたクラスパス上から必要な.javaや.classファイルを探してコンパイルや実行を行う。それを設定するパス。
以下の例では-cpオプションを使用してクラスパスを指定していたが、$CLASSPATH変数を設定することでもパスを通すことが可能。
例(コンパイルを例にしているが実行時も考え方は同じ):仮にsrc配下にmainフォルダがあり、そこにMain.javaがあるとする。
cd src/main #src/mainに移動
javac Main.java #見覚えあるやつ
この時、クラスパスを指定していないが、その場合はカレントディレクトリからMain.javaを探す。
クラスパスを指定すると以下のような記述になる。
javac -cp . Main.java #カレントディレクトリをクラスパスとして指定
今の例はクラスパスを指定しなくても良い例だったが、指定する必要がある例をあげる。
src/main/subというディレクトリがあり、そこにSub.javaを作成したとする。
そして、Main.javaにSubクラスをインスタンス化する記述を追記する。
public Main.java {
public static void main(args[]){
Sub sub1 = new Sub();
}
}
この時、はじめの例と同様、以下コマンドを実行するとエラーとなる。
cd src/main #src/mainに移動
javac Main.java #実行時エラー
なぜかというと、クラスパスがsrc/mainにしか通っておらず、Main.javaでインスタンス化しているSubクラスをコンパイラは見つけられないためである。
修正後は以下。
javac -cp .;./sub Main.java #カレントディレクトリ(main),subをクラスパスとして指定
このように、javaをコンパイル・実行する際はクラスパスを意識する必要がある。
また詳細は省略するが、標準ライブラリでないパッケージをimportする際にもクラスパスを指定する必要がある。(ちなみにjava.utilなどの標準ライブラリは勝手にクラスパスが通っているらしい)
Discussion