빌드 도구없이 jar파일 만들어보기 1탄과 다르게 2탄에서는
외부 라이브러리를 사용할 경우 어떻게 빌드하는지 이번에도 마찬가지로 빌드 도구를 사용하지 않고 진행해보겠다.
Calculator.jar 파일을 만들어 볼 것이다. 앞에것을 복습해 볼겸 한 번 해보길 바란다.
1. calculator.jar 만들기
1. 프로젝트 생성
2. package 생성(com.nhnacademy.hello.util)
3. util package에 Claculator.java 생성, 아래 코드 추가
package com.nhnacademy.hello.util;
public final class Calculator {
private Calculator(){
throw new IllegalStateException("Utility class!");
}
public static int plus(int a, int b){
return a+b;
}
public static int subtract(int a, int b){
return a-b;
}
public static int multiply(int a, int b){
return a*b;
}
public static int divide(int a, int b){
return a/b;
}
}
4. 단, 주의할 점 jar 생성시 `--main-class`는 지정하지 않는다.
왜? 이 calculator.jar의 목적은 단순 실행 목적이 아니라 어떤 A라는 프로젝트에서 계산하는 클래스를 만드는 대신 calculator.jar를 가져다 사용하기 위함이 목적이다.
2. 1탄에서 만든 hello 프로젝트에서 calculator.jar를 추가하고 실행해보기
1. 1탄에서 만든 hello 프로젝트를 열어준다.
2. lib 폴더에 calculator.jar를 넣어준다. 저장버튼이나 refresh 해보자.

주의할 점 1. settings.json을 열었을 때 아래 사진처럼 이미 작성된 코드가 있을 것이다.

주의할 점 2. 만약 해당 내용이 없다면 아래 코드를 추가해준다.
{
"java.project.referencedLibraries": [
"lib/**/*.jar"
]
}
주의할 점 3.`lib/calculator.jar`위치하면 자동으로 Refferenced Libraries에 추가됨.
Refferenced Libraries의 위치는 아래 사진에서 확인 가능하다.

3. 이제 1탄에서 만들었던 Main.java에 가서 아래 코드대로 내용을 추가한다.
package com.nhnacademy.hello;
import com.nhnacademy.hello.util.Calculator;
public class Main {
public static void main(String[] args) {
System.out.println("Hello java!");
System.out.println("더하기:" + Calculator.plus(20,10));
System.out.println("빼기:" + Calculator.subtract(20,10));
System.out.println("나누기:" + Calculator.divide(20,10));
System.out.println("곱하기:" + Calculator.multiply(20,10));
}
}
4. 실행 한번 해보자.

3. hello.jar를 만들어보자!
1. 원래 있던 hello.jar 삭제 해준다.
직접 오른쪽 클릭 -> delete 삭제하거나 아래 명령어 입력(터미널 현재 위치 확인)해서 삭제
rm hello.jar
2. 이제 컴파일 해보자
javac ./src/com/nhnacademy/hello/*.java -d ./out/

어라라...? 갑자기 에러가 뜬다....
에러 이유에 대해서 한 번 고민해보고 꼭 아래 글을 보는 것을 추천한다.
err : package com.nhnacademy.hello.util does not exist ~~~ 라고 뜬다.
이유는 크게 두 가지로 볼 수 있는데
a. 클래스 파일이 어디에 있는지 컴파일러가 알아야 한다.
a-1. 타입 검사 및 유효성 확인 : 컴파일러는 소스 코드에서 사용된 모든 클래스의 타입 정보를 확인 해야한다. 즉, Main.java에서 Calculator클래스의 메서드를 호출할 때, 해당 메서드의 시그니쳐(메서드 이름과 파라미터리스트)를 알아야한다. 올바른 타입으로 메서드가 호출되는지 확인해야 하니깐.
a-2. 메서드 시그니처 확인 : 1-1에서 언급했듯이 외부 라이브러리의 메서드를 호출할 때, 메서드 시그니쳐가 올바르게 호출되고 있는지 컴파일러가 확인해야 한다.
a-3. 호출 경로 설정 : 소스 코드에서 사용된 외부 라이브러리의 클래스들을 참조해 해당 메서드가 어디서 어떻게 호출되는지 알아야한다. 이 과정은 실행을 시도하는 것이 아니라, 메서드 호출에 필요한 모든 정보가 컴파일 시점에서 정확한지 검증하는 과정이다.
b. 의존성 관리
즉, 컴파일을 통해 내가 작성한 코드에 문제가 없는지 검증하는 과정에서 실제로 hello 프로젝트에는 calculator.java를 작성한 적이 없다. 근데 hello프로젝트에 있는 Main.java에서는 Calculator클래스에 있는 메서드들을 사용하고 있다.
외부에서 가져온 calculator.jar파일안에 실제 calculator.class가 있기 때문에 calculator.jar가 어디있는지 알려줘야 컴파일 할때 정상적으로 할 수 있다는 말이다.
3. 클래스패스를 적어주고 컴파일 해보자.
javac ./src/com/nhnacademy/hello/*.java -d ./out/ --class-path ./lib/calculator.jar

4. 이제 jar 파일을 만들어보자
cd out
jar --file hello.jar --main-class com.nhnacademy.hello.Main -c ./com

5. hello.jar 실행해보자

에엥..? 또 에러가 뜬다...
hello Java!는 출력 되었는데 또 Calculator클래스의 메서드를 사용하는 부분부터 NoClassDefFoundError가 발생했다....
한 번 고민해보고 밑에 더보기를 보는것을 추천한다.
결론부터 말하자면 마찬가지로 실행할 때 클래스패스를 같이 적어서 실행해줘야한다.
처음에 왜 안될까?와 왜 클래스패스를 적어줘야하지?를 거의 하루동안 고민했던거 같다..
컴파일 할 때의 명령어와 jar파일을 만들 때 명령어를 다시 봐보자.
1. 컴파일 할 때
javac ./src/com/nhnacademy/hello/Main.java -d ./out/ --class-path ./lib/calculator.jar
--class-path로 지정했다고 해서 calculator.jar파일 안에 있는 calculator.class까지 같이 컴파일 된것이 아니다!!
javac 뒤에 경로를 보면 ./src~~/Main.java 즉 Main java파일만 class파일로 변형한 것이다.
2. jar파일 만들 때
jar --file hello.jar --main-class com.nhnacademy.hello.Main -c ./com

위의 명령어도 유심히 보면 out폴더 아래에있는 ./com밑에 있는 리소스들을 jar로 만들지 Calculator와 관련된 파일은 존재하지 않는다.
즉, hello.jar안에는 Calculator클래스에 대한 소스코드는 전혀 포함되어있지 않기 때문에, 실제 Calculator.jar가 있는 위치를 알려주면서 실행해야한다.

나 같은 경우 실제 calculator.jar의 위치를 고려해서 명령어를 작성한다면
최종적으로 아래와 같다.
java -cp "./hello.jar:/Users/insub/Desktop/hello/hello/lib/calculator.jar" com.nhnacademy.hello.Main
6. 클래스패스를 같이 입력하고 jar를 실행해보자.
java -cp "./hello.jar:/Users/insub/Desktop/hello/hello/lib/calculator.jar" com.nhnacademy.hello.Main
-cp "실행할 jar파일의 위치:외부라이브러리위치"

근데 여기서 이전에 jar 파일을 실행할 때 -jar hello.jar 입력했을 때 처럼 아래 명령어로 입력하면 또 오류가 난다
java -cp "./hello.jar:/Users/insub/Desktop/hello/hello/lib/calculator.jar" -jar hello.jar
궁금한 사함은 더보기 클릭ㄱㄱ
1. -jar 옵션 vs -cp 옵션:
- -jar hello.jar: 이 옵션은 hello.jar 안에 있는 MANIFEST.MF 파일의 Main-Class 속성에서 지정된 메인 클래스를 찾아 실행합니다. 이때 클래스패스 설정(-cp)이 무시됩니다. 즉, 클래스패스에 설정된 외부 라이브러리(JAR 파일)가 적용되지 않으므로 calculator.jar를 찾을 수 없어 NoClassDefFoundError가 발생할 수 있습니다.
- com.nhnacademy.hello.Main: 이 명령어는 명시적으로 Main 클래스를 실행하고, 클래스패스(-cp)에 지정된 모든 JAR 파일(즉, hello.jar와 calculator.jar)을 함께 참조합니다. 따라서 외부 라이브러리까지 포함되어 정상적으로 실행됩니다.
2. 클래스패스 처리:
- -jar 옵션: -jar 옵션을 사용하면, JAR 파일 내 MANIFEST.MF 파일의 클래스패스 설정만 참조합니다. 즉, 클래스패스(-cp)를 무시하기 때문에, 외부 JAR 파일인 calculator.jar를 찾지 못하게 됩니다.
- -cp 옵션: -cp 옵션을 사용하여 클래스패스를 직접 지정하면, 명시된 모든 JAR 파일과 디렉터리가 클래스패스에 추가됩니다. 이 경우, hello.jar와 calculator.jar가 함께 클래스패스에 포함되어 메인 클래스(Main)에서 Calculator 클래스가 정상적으로 참조될 수 있습니다.
3. 차이 요약:
- -jar hello.jar: 클래스패스 설정이 무시되므로, 외부 라이브러리를 찾지 못해 오류가 발생할 수 있습니다.
- com.nhnacademy.hello.Main: 명시적으로 클래스와 클래스를 실행하며, 클래스패스에서 모든 JAR 파일이 참조되므로 정상적으로 외부 라이브러리를 사용할 수 있습니다.
다음 포스팅에는 Maven을 이용해서 빌드하는 과정을 정리할 것이다.
이것으로 빌드도구 없이 빌드해보기를 마치겠다.
'개인공부 > Maven' 카테고리의 다른 글
| 5. Maven Archetype Plugin, Maven 프로젝트 생성 (1) | 2024.10.13 |
|---|---|
| 4. Maven (3) | 2024.10.13 |
| 2. 빌드 도구없이 jar파일 만들어보기 1탄 (4) | 2024.10.12 |
| 1. 빌드 도구 (1) | 2024.10.12 |
댓글