728x90


자바 프로젝트의 목적은 여러가지가 있을 것이다.

보통 사용하는 목적은 jar,war같은 아카이브 형식으로 만들거나

main을 실행시키는 실행파일을 목적으로 하는것을 만들게 된다.

하지만 일반적으로 대다수의 프로젝트의 목표는 jar나 war파일을 만드는데 있다.

war파일의 경우는 조금 뒤에 논하기로 하자. 일단 여기서는 jar파일을 만드는 방법에 대해서 알아보도록 하자.


jar파일은 크게 보면 두종류가 있는데 실행 불가능한 jar와 실행 가능한 jar가 있다.

먼저 실행 불가능한 jar를 만드는 방법부터 시행해보도록 하자.

예제 프로젝트는 6장의 예제를 참조하라.


<?xml version="1.0"?>
<project name="AntTest" default="main" basedir=".">
<property name="Name" value="Ant Test"></property>
<property name="name" value="anttest"></property>
<property name="groupid" value="net.theceres.anttest"></property>
<property name="project.version" value="1.0.0"></property>

<property name="src.dir" value="src"></property>
<property name="build.dir" value="build"></property>
<property name="classes.dir" value="${build.dir}/classes"></property>
<property name="jar.dir" value="${build.dir}/jar"></property>

<target name="clean">
<delete dir="${build.dir}"></delete>
</target>
<target name="init">
<mkdir dir="${build.dir}"></mkdir>
<mkdir dir="${classes.dir}"></mkdir>
</target>
<target name="compile" depends="init">
<javac srcdir="${src.dir}" destdir="${classes.dir}" includeantruntime="false">
</javac>
</target>
<target name="jar" depends="compile">
<jar destfile="${jar.dir}/${name}-${project.version}.jar" basedir="${classes.dir}">
</jar>
</target>
<target name="run" depends="compile">
<java classpath="${classes.dir}" classname="${groupid}.Main">
</java>
</target>
<target name="main" depends="clean,jar">
</target>
</project>

이 ant의 결과 ant라는 명령어를 치면 더이상 main을 시행하지 않고 jar파일을 생성하게된다.

설정이 몇개 추가되었는데 잘보면 몇줄 추가 되지 않았다.

바뀐 부분을 위주로 설명을 하자면 먼저 주 타겟인 main이 더 이상 java를 시행하지 않는다.

이 부분은 run으로 분리된다. 즉 이제부터 시행하고 싶다면 ant라는 명령어가 아닌

ant run이라는 명령어를 사용하게 할것이다.

이 프로젝트의 목표가 더이상 main의 실행이 아닌것이다. 물론 main의 실행이 목표라면 기존그대로 사용해도된다.

혹은 main의 depends를 변경하여 run을 실행하게 해도 될 것이다.


먼저 jar파일의 위치를 선정한다. 보통의 경우에는 build밑에 jar라는 폴더를 만들고 그 아래에 위치하게 한다.

아주아주아주 특별한 경우가 아니라면 이 약속은 지킨다.

jar 엘리먼트 내부에는 일반적으로 destfile이 존재하며 이의 역할은 그냥 만들어질 파일 이름을 경로와 포함해서 집어넣는 것이다.

위의 예제의 경우 jar경로에 name-project.version이라는 이름으로 jar파일을 만드는 것이다.

위의 소스를 실행하면 해당 jar파일이 만들어진다.

이 때 jar파일을 만드는데 사용할 디렉터리는 보통 classes.dir을 사용한다.

따라서 basedir 속성에 class.dir을 넣으면된다.

이제 jar파일이 만들어진다. 그럼 제대로 만들어졌는지 해당경로를 찾아가서 압축을 풀어보라.



제대로 실행됬음을 알 수 있다.

그럼 이번에는 실행이 되는 jar파일을 만들어보자.

jar파일을 호출만으로 실행하려면 manifest파일이 존재해야한다.

일일히 만들어서 집어넣는 방법도 있지만 그다지 좋은 방법은 아니다.

다만 더 좋고 편리한 방법을 ant는 제공해 준다.


실행가능한 jar파일을 만드는 법


요즘 IDE에서 제공해주는 기능들 인지라 이거 은근히 모르는 사람이 많다.

jar파일에 Main함수를 명시적으로 호출해줘서 처리해주는게 아니라

jar를 부르는 것만으로 처리하는 방법은 META-INF폴더안에 MANIFEST.MF파일을 만든다.

그리고 Main-Class: "main클래스를 패키지경로까지 포함해서"를 적어준다. 참고로 쌍따옴표는 생략한다.

아래는 실행가능 jar파일을 만들기 위한 예제이다.


mkdir -p build/classes/META-INF

echo "Main-Class: net.theceres.anttest.Main" > MANIFEST.MF

find ./src -name *.java > sources_list.txt

javac -d build/classes -cp build/classes @sources_list.txt

jar cvfm new.jar MANIFEST.MF -C build/classes .

java -jar new.jar


예제는 필자의 6장 예제에서 실행한 코드이다.

여기서 추가된 점은 프로젝트의 베이스디렉터리에 MANIFEST.MF파일을 만들었다는것,

그리고 jar 옵션에 m을 추가하고 MANIFEST.MF를 지정해줬다는 점이다.

MANIFEST.MF파일의 경우 굳이 리다이렉션이 아니라도 만들 수 있으므로

명령어가 익숙치 않다면 메모장을 열고 Main-Class: net.theceres.anttest.Main을 입력한후

저장하면된다. 당연히 저장위치는 현제 베이스 디렉터리(프로젝트의 바로 하위)이다.

그리고 마지막에 java -jar new.jar를 시행하면 jar파일이 시행된다.


보다시피 jar파일에 manifest를 넣는 작업은 귀찮고 것보다 jar를 만드는 과정자체가 귀찮다.

이를 자동화 할 수 있다면 정말 좋을 것이고 아래에는 자동화 하는 방식을 알려줄 것이다.



<?xml version="1.0"?>
<project name="AntTest" default="main" basedir=".">
<property name="Name" value="Ant Test"></property>
<property name="name" value="anttest"></property>
<property name="groupid" value="net.theceres.anttest"></property>
<property name="project.version" value="1.0.0"></property>

<property name="src.dir" value="src"></property>
<property name="build.dir" value="build"></property>
<property name="classes.dir" value="${build.dir}/classes"></property>
<property name="jar.dir" value="${build.dir}/jar"></property>

<target name="clean">
<delete dir="${build.dir}"></delete>
</target>
<target name="init">
<mkdir dir="${build.dir}"></mkdir>
<mkdir dir="${classes.dir}"></mkdir>
</target>
<target name="compile" depends="init">
<javac srcdir="${src.dir}" destdir="${classes.dir}" includeantruntime="false">
</javac>
</target>
<target name="jar" depends="compile">
<jar destfile="${jar.dir}/${name}-${project.version}.jar" basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="net.theceres.anttest.Main"></attribute>
</manifest>
</jar>
</target>
<target name="run" depends="compile">
<java jar="${jar.dir}/${name}-${project.version}.jar" fork="true">
</java>
</target>
<target name="main" depends="clean,jar">
</target>
</project>

총 2가지의 엘리먼트들이 변경되었다. jar와 run이 변경되었으며 변경점을 한번보자.

먼저 jar에서는 manifest속성이 추가되었다. 그리고 attribute속성으로 메인클래스를 manifest의 속성으로 넣을 수 있다.

참고로 attribute의 name속성의 캐이싱은 Train casing으로한다. 이유는 필자도 모른다...

Train casing이므로 단락은 -와 대문자로 끊어준다.

그리고 마지막에 fork속성을 true로 준다. 이 속성은 병렬화 처리할때 fork해서 처리할지 물어보는건데

다른건 몰라도 jar를 실행할때 이속성이 없다면 아예 실행되지 않는다.

이제 테스트를 해보자.



제대로 실행됨을 확인할 수 있다.

jar파일안에 manifests가 정상적으로 들어갔음도 알 수 있다.

+ Recent posts