Java classpath (Windows) 관리하기 (한글)

    Windows에서 classpath를 관리하는 방법


    난이도 : 초급

    Elliotte Harold, Adjunct Professor, Polytechnic University

    2007 년 1 월 16 일

    classpath 는 자바™ 플랫폼에서 가장 복잡한 부분 하나이지만, 전문 자바 프로그래머가 되려면 반드시 마스터해야 합니다. Elliotte Rusty Harold classpath sourcepath Windows 플랫폼에서 사용하는 방법을 설명합니다. UNIX 또는 Mac OS X 사용자라면, 관련 기술자료를 참조하십시오.

    classpath는 자바 런타임과 파일시스템간 연결이다. 컴파일러와 인터프리터가 로딩할 .class 파일들을 검색할 장소를 정의한다. 기본 개념은, 파일시스템 계층이 자바 패키지 계층을 미러링 하고, classpath가 파일시스템에서 어떤 디렉토리가 자바 패키지 계층에 대한 루트의 역할을 할 것인지를 지정하는 것이다.

    안타깝게도, 파일시스템은 복잡하고, 플랫폼 의존성이 크며, 자바 패키지와 완벽하게 들어맞지 않는다. 따라서, classpath는 신참 사용자와 숙련된 자바 프로그래머 모두에게서 가시와 같은 존재가 되었다. 자바 플랫폼에서도 환영을 받는 존재도 아니다. 지독하게도 솔루션이 나오지 않는 소소한 문제들을 해결하느라 많은 노력을 기울여야 한다.

    Eclipse 같은 훌륭한 IDE는 classpath 관리의 어려움을 덜어주기는 하지만, 어디까지나 모든 것이 잘 작동하고 있을 경우에만 해당된다. (어떤 것이나 늘 잘못되기 마련이다.) 결국, 모든 자바 프로그래머는 classpath를 완전히 이해해야 한다. 완벽한 통달만이 classpath에서 발생하는 가시 같은 문제들을 해결할 수 있다.

    이 글에서는, Windows 플랫폼에서 자바 classpath(관련 sourcepath 포함)에 대해 알아야 할 모든 것을 망라했다. 관련 기술자료에서는 UNIX와 Mac OS X 플랫폼을 기준으로 설명했다. 이 글은 대부분의 classpath 문제들을 해결할 수 있는 좋은 가이드가 될 것이다.

    패키지 구조

    classpath는 소스 코드부터 시작하겠다. 모든 클래스는 패키지에 속해 있고, 이 패키지는 표준 네이밍 규약을 따라야 한다. 간단히 정리하면 다음과 같다. 패키지 이름은 com.example 또는 edu.poly처럼, 두 개의 도치된(reversed) 도메인 이름으로 시작한다. 그 다음에는 패키지의 내용을 설명하는 한 개 이상의 단어가 나온다. 예를 들어, 도메인 네임 elharo.com이 있고, Fraction 클래스를 작성한다면, 다음과 같은 패키지 형태가 될 것이다.

    • com.elharo.math
    • com.elharo.numbers
    • com.elharo.math.algebra.fields

    도 치된 도메인 네임 다음에는, 한 단어로 된 서브패키지(subpackage) 이름만 사용한다. 단어를 생략하지 말고, 모든 단어를 정확하게 작성한다. 필요할 경우에는, 스펠 체커를 사용한다. classpath 관련 문제들 대부분이 소스 코드에 한 단어를 사용하는 데서 기인하고, 파일시스템의 단어와 약간 다른 스펠링 또는 축약 때문에 발생한다. 가장 현명한 방법은 정확한 철자를 사용하는 것이다.

    전체 패키지 이름은 소문자로 하고, 일반적으로 대문자로 표기하는 고유 명사나 두문자어도 소문자로 한다. Windows는 파일 이름에 대/소문자를 구별하지 않지만, 자바와 일부 유닉스 파일시스템은 구분한다. 시스템들 간 파일을 이동할 때, 케이스(case)는 문제를 일으키는 주요 원인이다.

    패키지 이름은 오직 ASCII 문자들로만 구성된다. 컴파일러는 Hebrew, Cyrillic, Greek, 기타 스크립트로 작성된 패키지 이름들을 허용하지만, 많은 파일 시스템들은 그렇지 않다. 이러한 패키지 이름들은 디렉토리 이름으로서의 이중 기능을 할 필요가 없다. 자바 패키지와 클래스 이름들은 Unicode이지만 FAT을 포함하여, 많은 파일시스템들은 아직 Unicode 방식이 아니다. 안타깝게도, 여전히 FAT 파일시스템들이 많이 남아있다. 다른 디폴트 인코딩을 가진 시스템으로 파일을 복사하면 컴파일러와 인터프리터가 올바른 클래스를 찾을 수 없다.

    폐기용(Throwaway) 코드

    단 한번 실행한 후에 바로 폐기할 클래스를 작성할 경우, 예를 들어, API를 테스트 하기 위해 클래스를 작성했다면, 이것을 패키지에 둘 필요가 없다. 하지만, 한 번 이상 사용될 클래스는 패키지에 있어야 한다.

    패 키지 이름에 인색하게 굴지 말라! 장기적으로 볼 때 큰 재앙이 될 수 있다. 도메인 이름이 필요하면, 구매해도 좋다. 이름이 너무 길다면, 짧은 것을 구매하라. (나는 xom.nu를 샀기 때문에, 나의 패키지 접두사는 단 여섯 문자뿐이다.) 클래스를 디폴트 패키지(클래스에 패키지 문을 추가하지 않을 경우 얻게 되는 패키지)에 두지 말라. 패키지 액세스가 객체 통신을 금하면, 더 많은 퍼블릭 메소드를 클래스에 추가하라. 한 번 이상 사용되는 모든 클래스는 패키지에 있어야 한다.

    Windows 설정하기

    파 일 확장과 경로는 자바와 Windows에 매우 중요하다. 따라서, 다음 단계를 시작하기 전에, 이것부터 검토해야 한다. 파일 이름의 숨겨진 부분은 엔드 유저에게는 허용될 수도 있겠지만(나도 이것이 의심스럽긴 하다.), 개발자에게는 그렇지 않다. 이를 해결하려면, Windows Explorer의 디폴트 설정을 수정해야 한다.

    우선, Windows 데스크탑에서 폴더를 연다. 어떤 것이든 상관 없다. Tools 메뉴로 가서 Folder Options를 선택한다. 다이얼로그에서, 다음과 같이 세 가지 옵션들이 설정되었는지를 확인한다. (그림 1)

    • "Display the full path in the address bar" 항목에 체크가 되어 있어야 한다.
    • "Display the full path in title bar" 항목에 체크가 되어 있어야 한다.
    • "Hide file extensions for known file types" 항목은 체크가 되어 있지 않아야 한다.

    그림 1. Windows Explorer 옵션

    "Show hidden files and folders" 옵션도 체크해야 한다. 이것은 자바 작동에는 많은 영향을 끼치지 않지만, 개인적으로 내가 무슨 작업을 하고 있는지를 볼 수 있는 것이 좋다. 이 옵션을 설정하면 어디서, 무엇을 하는지에 대한 상세를 볼 수 있고, 문제 해결도 훨씬 쉬워진다.




    디렉토리 구조

    다음 단계는 패키지 구조에 맞게 소스 파일을 구성하는 단계이다. 깨끗하고, 비어있는 디렉토리를 만든다. 이 글의 목적에 맞게 이름을 project로 지었다. C:\project처럼, 루트 레벨에 두는 것이 가장 쉽다. 데스크탑 또는 Documents and Settings 폴더에 저장할 수도 있다. 더 길고 복잡한 타이핑을 해야 하는 명령어를 만들 것이기 때문에, 필요한 경우에만 그렇게 한다. (Windows XP 또는 이후 버전을 사용하고, 관리 권한이 없다면 선택권이 없다. 싱글 유저 시스템에서, 관리 권한으로 실행한다면 훨씬 쉬워진다.)

    무엇을 하든지 간에, 이 디렉토리(또는 그 어떤 것이든)를 JDK 폴더에는 넣지 말아야 한다. (예를 들어, C:\jdk1.6.0 or C:\Program Files\Java\j2sdk1.5.0_09). JDK와 JRE 디렉토리는 초기 설치 후에는 건드리지 않아야 한다.

    Project 디렉토리 안에, 두 개의 디렉토리를 더 만든다. bin과 src이다. (어떤 사람들은 build와 source라는 이름을 더 선호하기도 한다.)

    그런 다음, src 디렉토리 안에, 패키지 계층을 모방한 계층을 만든다. 예를 들어, com.elharo.math.Fraction이 라고 하는 클래스가 있다면, src 디렉토리에 com 디렉토리를 넣는다. 그런 다음, com 디렉토리 안에 elharo 디렉토리를 만든다. 그리고 나서, elharo 디렉토리 안에 math 디렉토리를 넣는다. 마지막으로, math 디렉토리 안에 Fraction.java를 넣는다. (그림 2)


    그림 2. 디렉토리 구조는 패키지 구조를 따른다.

    중 요: src 디렉토리에 소스 코드 외 다른 것을 절대 넣지 말라. 그곳에 들어갈 유일한 파일은 .java 파일들이다. 가끔 이 디렉토리에 .html(Javadoc) 또는 다른 유형의 소스 코드를 넣는 경우도 있다. 하지만, .class 파일이나 다른 생성물들을 이 계층에 넣어서는 안된다. 큰 문제가 생길 것이다. javac 컴파일러의 경우, 조심하지 않는다면 반드시 문제를 일으킨다. 다음 섹션에서 이러한 문제를 해결하는 방법을 설명하겠다.




    컴파일

    자바 코드 컴파일은, 여러 가지 관련 사항들을 트래킹 해야 하기 때문에 손이 많이 간다.

    백 슬래시(Back slash)와 포워드 슬래시(forward slash)

    자바 언어를 고안한 유닉스 프로그래머는 컴파일러가 Windows 백 슬래시 대신 유닉스 스타일의 포워드 슬래시를 허용하도록 했다. 따라서, 다음 명령어 역시 작동한다.

    C:\project> javac src/com/elharo/math/Fraction.java

    Windows에서는 언제나 백 슬래시를 사용하는 것이 상책이다.

    • 컴파일 대상 파일
    • 컴파일러가 대상 파일이 반입하는 .java 파일을 검색할 디렉토리
    • 컴파일러가 대상 파일이 반입하는 .class 파일들을 검색할 디렉토리
    • 컴파일러가 아웃풋을 둘 디렉토리

    기본적으로, javac 컴파일러는 이 모든 것이 현재 실행 디렉토리라고 간주하는데, 대게는 우리가 원하는 것이 아니다. 결국, 컴파일 할 때 엘리먼트들을 명확하게 지정해야 한다.

    컴파일 대상 파일

    우선, 컴파일 하고자 하는 .java 파일을 지정해야 한다. 이것은 현재 실행 디렉토리에서 그 파일로 가는 경로로 주어진다. 예를 들어, 그림 1처 럼, project 디렉토리를 생각해 보자. 이 디렉토리에는 src 디렉토리가 있다. src 디렉토리에는 com 디렉토리가 있고, com 디렉토리에는 예제 디렉토리가 포함되어 있다. 여기에는 Fraction.java 파일이 있다. 다음 명령행이 이것을 컴파일 한다.

    C:\project> javac src\com\elharo\math\Fraction.java

    경로가 정확하지 않다면, 다음과 같은 에러 메시지를 받게 된다.

    error: cannot read: src\com\example\mtah\Fraction.java

    에러 메시지가 생기면, 경로를 보면서 철자가 올바르게 쓰였는지를 확인한다. 이 경우, “math” 단어에서 두 번째와 세 번째 문자가 바뀌었다.

    스펠링 에러를 찾지 못했다면, 다음과 같은 dir 명령어를 실행하여, 이 파일이 있어야 할 곳에 있는지를 확인한다.

    C:\project\src> dir src\com\example\math
    ls: src/com/example/math: No such file or directory

    이 문제는 잘못 입력된 경로를 나타내지만, 여러분이 생각한 디렉토리에 있지 않다는 것도 의미한다. 이 예제에서, 현재 실행 디렉토리가 project 디렉토리인지를 확인했다. 명령행에서 C:와 > 사이의 텍스트를 체크하여 제 위치에 있는지를 확인한다. 이 예제에서는, C:\project에 있어야 하는데, 실제로는 C:\project\src에 있다는 것을 알게 될 것이다.

    아웃풋의 위치

    신 택스 에러가 없다고 가정하고, javac는 컴파일 된 .class 파일을 상응하는 .java 파일이 있는 같은 디렉토리에 둔다. 이것은 우리가 원한 것이 아니다. .class와 .java 파일을 섞어 놓으면, 컴파일 된 파일들을 지우기가 매우 어렵다. 실수로 .java 파일들을 지울 수도 있다. 이는 깨끗한 구현도 문제 거리로 만들며, 버저닝 문제도 일으킨다. 또한 바이너리를 배포할 때, 컴파일 된 .class 파일들만 압축하기도 힘들다. 따라서, 완전히 다른 디렉토리에 저장하도록 컴파일러에 명령해야 한다. -d 스위치는 아웃풋 디렉토리(대게 bin, build, classes)를 지정한다.

    C:\project> javac -d bin src\com\elharo\math\Fraction.java

    아웃풋은 그림 3과 같다. javac가 완전한 com\elharo\math 디렉토리 계층을 만들었다. 여러분이 직접 할 필요가 없다.


    그림 3. 병렬 소스와 컴파일 된 계층

    sourcepath

    자바가 소스 파일들을 검색할 디렉토리는 sourcepath이다. 여기에서는, src 디렉토리이다. 이 디렉토리에는, 자신들의 디렉토리로 구성된, 소스 파일의 계층이 포함되어 있다. com 디렉토리도, src\com\elharo\math 디렉토리도 아니다.

    대부분의 프로젝트는 한 개 이상의 클래스와 패키지를 사용한다. 이것은 import 문과 완전한 패키지 자격을 갖춘 클래스 이름에 의해 연결된다. 예를 들어, com.elharo.gui에 새로운 MainFrame 클래스를 만든다고 해보자.(Listing 1)


    Listing 1. 한 패키지의 클래스가 또 다른 패키지의 클래스를 반입할 수 있다.


                                   
    package com.elharo.gui;

    import com.elharo.math.*;

    public class MainFrame {

      public static void main(String[] args) {
        Fraction f = new Fraction();
        // ...
      }

    }

    이 클래스는 MainFrame 클래스와는 다른 패키지에 있는 com.elharo.math.Fraction 클래스를 사용한다. 소스 설정은 그림 4과 같다. (이전 단계의 컴파일 된 아웃풋을 삭제했다. 언제든 다시 컴파일 할 수 있다.)


    그림 4. 여러 패키지의 소스 구조

    이제, 전에 했던 것처럼 MainFrame.java를 컴파일 할 때 어떤 일이 발생하는지 보자.


    Listing 2. MainFrame.java 컴파일


                                   
    C:\project> javac -d bin src\com\elharo\gui\MainFrame.java
    src\com\elharo\gui\MainFrame.java:3: package com.elharo.math does not exist
    import com.elharo.math.*;
    ^
    src\com\elharo\gui\MainFrame.java:7: cannot find symbol
    symbol  : class Fraction
    location: class com.elharo.gui.MainFrame
      private Fraction f = new Fraction();
              ^
    src\com\elharo\gui\MainFrame.java:7: cannot find symbol
    symbol  : class Fraction
    location: class com.elharo.gui.MainFrame
      private Fraction f = new Fraction();
                               ^
    3 errors

    javac가 MainFrame.java를 어디에서 찾아야 할 지를 알지만, Fraction.java를 어디에서 찾아야 할지 모르기 때문에, Listing 2에 에러가 생겼다. (매칭 패키지 계층들을 인식하는 것으로도 충분하다고 생각했는데, 그렇지가 않다.) sourcepath를 지정해야 한다. 이것은 컴파일러가 소스 파일의 계층을 검색할 디렉토리를 지정한다. Listing 2에서는, src이다. 따라서, 나도 다음과 같이, -sourcepath 옵션을 사용한다.

    C:\project> javac -d bin -sourcepath src src\com\elharo\gui\MainFrame.java

    이제 프로그램은 에러 없이 컴파일 하고, 그림 5와 같은 아웃풋을 만들어 낸다. javac 역시 내가 컴파일 했던 파일에 의해 참조된 Fraction.java 파일을 컴파일 했다.


    그림 5. Multiclass 결과

    sourcepath에서 여러 디렉토리 컴파일 하기

    sourcepath 에 한 개 이상의 디렉토리가 생겼다. 반드시 그래야 하는 것은 아니지만, 콜론으로 구분되어 있다. 또 다른 프로젝트용 소스 코드를 관리할 로컬 src 디렉토리와 C:\Projects\XOM\src 디렉토리를 추가하고 싶다면, 다음과 같이 컴파일 할 수 있다.

    C:\project> javac -d bin -sourcepath src;C:\Projects\XOM\src
      src/com/elharo/gui/MainFrame.java

    이 명령어는 그 계층에서 발견된 모든 파일들을 컴파일 하지 않는다. 컴파일 되도록 분명히 요청했던 하나의 .java 파일에 의해 직/간접적으로 참조된 파일만 컴파일 한다.

    디렉토리 이름에서의 공간

    자 바 클래스나 패키지 이름에는 공백이 없다. 하지만, 가끔은 자바 패키지 디렉토리나 소스 파일을 포함하고 있는 디렉토리에 공백이 포함되기도 한다. Documents and Settings가 대표적인 예이다. 경로에 이러한 디렉토리들 중 하나를 추가해야 한다면, 관련 명령행 인자에 더블 쿼트를 사용해야 한다. 루트 C: 디렉토리에서, src 폴더가 C:\Documents and Settings\Administrator\project에 있다면, 다음과 같이 컴파일 해야 한다.

    C:\> javac -d bin -sourcepath "C:\Documents and Settings\Administrator\project"
     -classpath C:\lib\classes
     "C:\Documents and Settings\Administrator\project\src\com\elharo\gui\MainFrame.java"

    대부분의 경우, 프로그램의 컴파일이나 실행 전에 project 디렉토리로 변경하여 이러한 문제들을 피한다.

    java 파일용으로 하나의 소스 디렉토리가 있지만, 사전 컴파일 된 서드 파티 라이브러리가 있는 곳에, 클래스 또는 JAR 아카이브를 위한 여러 디렉토리도 가질 수 있다. 이것은 classpath의 역할이다.

    classpath 설정하기

    중대형 프로젝트에서, 매번 모든 파일들을 재 컴파일 한다는 것은 시간 낭비다. 다른 클래스나 bin 디렉토리에 같은 프로젝트의 독립된 부분들을 개별적으로 컴파일 및 저장함으로써 이러한 문제를 완화시킬 수 있다.

    클래스를 classpath에 추가하는 여러 가지 방법이 있다. 하지만, 여러분은 -classpath 명령행 스위치만 사용해야 한다. 이전에 컴파일 했던 또 다른 프로젝트에서 파일을 C:\lib\classes 디렉토리로 반입하고 싶다면? -classpath C:\lib\classes를 다음과 같이 명령행에 추가한다.

    C:\project> javac -d bin -sourcepath src -classpath C:\lib\classes
      src\com\elharo\gui\MainFrame.java

    두 개의 디렉토리, C:\project1\classes와 C:\project2\classes를 추가한다고 해보자. 콜론으로 구분하여 다음과 같이 추가한다.

    C:\project> javac -d bin -sourcepath src
      -classpath C:\project1\classes;C:\project2\classes
      src\com\elharo\gui\MainFrame.java

    물론, 원한다면, 다양한 형태의 상대 경로를 사용할 수 있다. project1과 project2가 현재 실행 디렉토리와 인접해 있다면(같은 부모 디렉토리를 갖고 있다면) 다음과 같이 한다.

    C:\project> javac -d bin -sourcepath src
      -classpath ..\project1\classes;..\project2\classes
      src\com\elharo\gui\MainFrame.java

    지금까지, 프로그램이 완전하고, 개별적으로 컴파일 된 서드 파티 라이브러리를 사용하지 않는 경우를 가정했다. 만약 그렇다면, 이들을 classpath에도 추가해야 한다. 라이브러리는 junit.jar 또는 icu4j.jar 같은 JAR 파일로 배포된다. 이 경우, classpath에 추가하는 것은, JAR 파일 그 자체이다. 이것을 포함하고 있는 디렉토리가 아니다. (본질적으로, JAR 파일은 컴파일 된 .class 파일들을 포함하고 있는 디렉토리의 역할을 한다.) 예를 들어, 다음 명령어는 classpath에 세 가지를 추가한다. C:\classes 디렉토리, 현재 실행 디렉토리에 있는 icu4j.jar 파일, E:\lib 에 있는 junit.jar 파일.

    C:\project> javac -d bin -sourcepath src
      -classpath C:\classes;icu4j.jar;E:\lib\junit.jar
      src\com\elharo\gui\MainFrame.java

    JAR 파일들은 .class 파일과 classpath에만 사용된다. .java 파일과 sourcepath에는 사용되지 않는다.

    상위 디렉토리

    여 기에서 내가 참조한 디렉토리들은 패키지 계층을 포함하고 있는 상위 디렉토리들이다. 이름이 패키지 이름들(com, elharo, math)과 매치하는 디렉토리들은 sourcepath 또는 classpath에 직접 포함되지 않는다.

    프로그램 실행하기

    프로그램을 성공적으로 컴파일 했고, 이제 실행할 준비가 되었다. 컴파일과 비슷하지만 더 간단하다. 프로그램을 실행할 때, 다음 두 가지를 지정하면 된다.

    • The classpath.
    • main() 메소드를 포함하고 있는 클래스의 전체 이름

    sourcepath를 지정할 필요가 없다.

    일반적으로, classpath는 프로그램을 컴파일 하기 위해 사용했던 것과 같은 classpath이다. 컴파일 된 아웃풋이 배치되었던 디렉토리가 추가된다. 예를 들어, 컴파일 명령어가 다음과 같고,

    C:\project> javac -d bin -sourcepath src
      -classpath C:\classes;E:\lib\junit.jar
      src\com\elharo\gui\MainFrame.java

    main() 메소드가 the class com.elharo.gui.MainFrame 클래스에 있다면, 다음과 같이 프로그램을 실행한다.

    C:\project> java -classpath bin;C:\classes;E:\lib\junit.jar
        com.elharo.gui.MainFrame

    명령행의 마지막 아이템은 클래스 이름이다. 파일 이름이 아니다. .java나 .class로 끝나지 않는다. 이 클래스는 classpath 어디에선가는 발견되어야 한다.




    다른 클래스들을 둘 곳

    컴 파일 할 때나, 실행할 때, 언제나 분명하게 classpath를 지정해야 한다. 파일을 둘 수 있는 다른 장소들이 있기 때문에, classpath에 추가되고, javac 컴파일러와 자바 인터프리터에 의해서 발견될 수 있다. 이 옵션들은 적은 양의 타이핑만 저장하고, classpath에 오래된 버전의 클래스를 둘 경우 디버깅에 많은 시간이 걸릴 것이다.

    예기치 않게 classpath로 와서 문제를 일으키는 클래스 하이딩을 찾을 장소를 설명하겠다. 이것은 서버 같이, 우리들이 제어할 수 없는 머신에서 발생한다.

    현재 실행 디렉토리

    요 청을 하든, 하지 않든 간에, 컴파일러는 현재 실행 디렉토리(.)를 classpath에 추가한다. 같은 디렉토리 안에 무엇이 있고, 없는지를 쉽게 잊는다. 따라서, 클래스나 계층들을 프로젝트나 홈 디렉토리에 두지 말라. 대신, .java 파일용 src 디렉토리와 bin 디렉토리에 명확하게 분리해서 저장해야 한다.

    CLASSPATH

    bin 디렉토리와 JAR 아카이브를 classpath에 직접 추가하는 것이 지겨울 것이다. 이때 CLASSPATH 환경 변수를 찾는다. 디렉토리와 JAR 아카이브를 단 한번만 CLASSPATH 환경 변수에 추가할 수 있다. javac나 자바를 실행할 때마다 경로를 입력할 필요가 없다.

    이 와 같은 유혹과 싸워라. 잘못된 클래스나 잘못된 클래스 버전을 로딩할 때 문제를 일으킬 것이다. 저장할 때 마다, 잘못된 클래스를 로딩했기 때문에 생긴 문제들을 디버깅 할 때 수백 번 취소당할 것이다. classpath를 자동화하고 타이핑을 피할 수 있는 더 나은 방법이 있다.

    jre\lib\ext

    jre\lib\ext 디렉토리에 있는 JAR 아카이브는 가상 머신에서 실행되는 모든 애플리케이션의 classpath에 추가된다. 이것이 안전해 보이지만, 디렉토리들을 CLASSPATH 환경 변수에 추가하는 것과 비슷한 실수이다. 조만간, 생각하지도 않았던 장소에서 잘못된 클래스 버전을 로딩하고, 이것을 디버깅 하느라 귀중한 시간만 낭비하게 될 것이다.

    이 문제는, 서버 측 애플리케이션을 전개할 때 특별히 위험하다. 전개할 서버에 jre/lib/ext 디렉토리에 추가 JAR 파일들이 없어야 한다. classpath에서 잘못된 버전의 JAR 아카이브로 생긴 문제들은, 증상을 인지하지 못하거나, 무엇을 찾아야 할지 모를 경우, 디버깅이 매우 어렵다. 이러한 문제들을 피하기 위해, 일부 프레임웍은 자바 코드의 일반 클래스 로딩 메커니즘을 우회하는 클래스 로더를 작성하기도 한다.

    jre\lib\endorsed

    jre\lib\endorsed에 있는 JAR 파일들은 가상 머신으로 실행되는 모든 애플리케이션의 classpath에도 추가된다. 차이점은, 이 파일들이 실제로 일반 classpath가 아닌 bootclasspath에 추가되고, 표준 클래스를 JDK로 대체할 수 있다. 이러한 방식은 XML 파서를 업그레이드 하고, VM에서 버그를 픽스할 때 유용하다.

    이 기술은 간편해 보이지만, 이 역시 장기적으로 볼 때는 위험하다. JDK 클래스로 대체해야 한다면, 런타임 시 -Xbootclasspath/p 옵션을 사용하여 잘못된 버전의 클래스를 로딩하는 것을 피한다.

    C:\project> java -classpath C:\classes
          -Xbootclasspath/p:xercesImpl.jar com.elharo.gui.MainFrame





    classpath 관리 자동화하기

    못 총(nail gun)을 집어 들기 전에 망치를 사용하는 방법부터 배워야 한다. 마찬가지로, 보다 강력한 툴을 찾기 전에 클래스를 직접 관리하는 것에 익숙해져야 한다. 하지만, 일단 명령행 툴셋을 익히면, sourcepath와 classpath를 자동으로 다루는 툴을 사용하고 싶을 것이다. 대게 이 툴들은 이 글에서 전개했던 라인에 따라 파일을 구성하면 작동한다.

    IDE

    Eclipse와 NetBeans 같은 통합 개발 환경은 classpath 관리의 일부를 자동화 한다. 예를 들어, 패키지 이름을 변경할 때, Eclipse는 상응하는 .java 파일을 매치하는 것으로 옮긴다. (그림 6)


    그림 6. Eclipse에서 classpath용 빠른 픽스

    하 지만, 이러한 IDE는, 특히 다른 툴과 다른 IDE와 통합해야 한다면, 파일시스템 상에 존재하며, 올바르게 설정되어야 한다. 이 툴의 주된 특징은 GUI 다이얼로그, 트리 뷰, 탭들이 명령행 스위치를 대체한다는 점이다. 하지만, 기본 파일 구조는 같다.

    Ant

    Ant는 빌드 프로세스를 자동화 하는 표준 툴이다. 디렉토리를 jre\lib\ext 또는 CLASSPATH 환경 변수에 두는 것과는 달리, Ant에서는 원스텝 빌드 프로세스를 만들 수 있다. 여전히, Ant build.xml 파일에 classpath를 설정하고, 올바른 디렉토리에 소스 파일들을 직접 저장해야 한다. 하지만, 컴파일 할 때마다 이것을 다시 지정할 필요는 없다.

    Maven

    Maven 은 빌드 프로세스와 관련 classpath 문제들을 구성 및 자동화 한다는 점에서 Ant 보다 더 향상되었다. Maven은, 단 몇 줄의 코드로도 간단한 프로젝트를 구현할 수 있도록, 합리적인 디폴트 설정을 제공한다. Maven이 찾을 수 있는 곳에 소스 파일을 두면 된다. 여전히, 파일 시스템 계층과 패키지 계층을 조정해야 한다. Maven은 삼자 라이브러리에 대한 의존성 관리에 특별히 뛰어나다. Ant 만큼 커스터마이징은 쉽지 않다.




    맺음말

    classpath는 문제가 많지만, 몇 가지 간단한 규칙을 사용하면 능히 다스릴 수 있다. 특히,

    • 모든 클래스는 패키지에 둔다.
    • 패키지와 클래스 네이밍 규약 및 대/소문자 규약을 엄격하게 지킨다.
    • 패키지 계층과 디렉토리 계층이 맞는지를 확인한다.
    • javac에는 언제나 -d 옵션을 사용한다.
    • \lib\ext에 어떤 것도 두지 않는다.
    • jre\lib\endorsed에 어떤 것도 두지 않는다.
    • .class 파일과 같은 디렉토리에 .java 파일을 두지 않는다.
    • 현재 실행 디렉토리에 .java나 .class 파일들을 두지 않는다.

    공유 사이트


    마 지막 팁: classpath와 관련한 많은 문제들은 디렉토리 이름을 잘못 입력했다거나, 잘못된 디렉토리에서 컴파일 하는 등 간단한 에러에서 진화한다. 무엇이 잘못되었는지 알 수 없다면, 동료나 친구에게 물어보고 문제를 찾아야 한다. 오히려 문제에 너무 집착하여, 다른 사람들 눈에는 명확하게 보이는 버그를 못 볼 수도 있다. 두 눈은 매우 효과적인 디버깅 방법이다.

    classpath는 분명 쉬운 것은 아니다. 하지만, 관리도 가능하다. 네이밍 규약, 명령행 인자, 디렉토리 구조에 신경을 쓴다면, 실수를 최소한으로 줄이고 프로그램을 컴파일 및 실행할 수 있을 것이다.

    기사의 원문보기


    참고자료

    교육



    제품 및 기술 얻기



    토론


    필자소개



    New Orleans 태생이다. 아내 Beth와 고양이 Charm 그리고 Marjorie와 함께 Brooklyn 근처 Prospect Heights에 살고 있다. Polytechnic University의 조교수로서 자바와 객체 지향 프로그래밍을 강의하고 있다. 그의 Cafe au Lait 웹 사이트는 가장 인기 있는 자바 사이트가 되었고, Cafe con Leche는 가장 대중적인 XML사이트가 되었다. Effective XML, Processing XML with Java, Java Network Programming, Java I/O, 2nd edition를 집필했다. 그는 현재 XML 프로세스용 XOM API, Jaxen XPath 엔진 Jester 테스트 툴 작업을 하고 있다.

'It's Code' 카테고리의 다른 글

Cygwin+MinGW32 참고  (0) 2009.06.26
FILE IO  (0) 2008.09.08
리눅스 커널 소스 디렉토리  (0) 2007.08.17
리눅스 커널 소스 (The Linux Kernel Sources)  (0) 2007.08.17
JAVAScript TIP  (0) 2007.08.10

+ Recent posts