저번 게시물에서 xml 을 대충(?) 살펴보았다.
이번에는 본격적으로 build.xml을 만들어 보겠다!
build.xml에서 여러 가지 일을 수행한다. 다운도 받고 뭐도 하고 뭐도 하고.. 그 중 필요한 것만.. 실은 아는 것만 코드로 만들 것이다. 우리가 원하는 hdfs.jar 을 만들기 위해 필요한 과정을 살펴보겠다.
1. 초기화 ( 디렉터리 생성 )
2. classpath 설정
3. java 컴파일
4. .jar 만들기
이 정도다.
우선 큰 틀을 만들자
vim build.xml
<?xml version="1.0"?>
<project name="hadoop" default="compile" basedir=".">
</project>
만들었으면 :w 저장한 번 하고!
굳이 설명할 필요가 없겠지만 간단하게 보면 프로젝트 이름은 hadoop이고 ant 명령을 실행했을 때 기본적으로 실행되는 target name은 "compile" 이라는 target이 실행된다. 그리고 기본 디렉터리 위치는 "." 현 위치라는 뜻이다.
그리고 필요한 변수선언(?)을 하면 되는데 나중에 필요할 때마다 추가하겠다.
그럼 시작을 위한 compile target을 만들어보자
<project> </project> 안에
<target name="compile" depends="compile-core-classes,compile-hdfs-classes" description="Compile core only">
</target>
을 추가한다. 그러면 순서는
ant라는 명령어가 들어오면 기본 target인 compile이라는 target이 실행되고 compile은 compile-core-classes, compile-hdfs-classes라는 target을 실행한다.
실제로 compile target은 아무 행동도 안 하고 두 개의 compile classes를 불러주는 행동만 한다.
그러면 compile-core-classes를 만들어보자
compile target이 끝나는 지점 (</target>) 밑에다가 추가한다.
<target name="compile-core-classes" depends="init">
<echo message="Compile core classes ..."/>
<taskdef classname="org.apache.jasper.JspC" name="jsp-compile">
<classpath refid="test.classpath"/>
</taskdef>
<javac
encoding="${build.encoding}"
srcdir="${core.src.dir}"
includes="org/apache/hadoop/**/*.java"
destdir="${build.classes}"
debug="${javac.debug}"
optimize="${javac.optimize}"
target="${javac.version}"
source="${javac.version}"
deprecation="${javac.deprecation}">
<compilerarg line="${javac.args} ${javac.args.warnings}"/>
<classpath refid="classpath"/>
</javac>
<copy todir="${build.classes}">
<fileset dir="${core.src.dir}" includes="**/*.properties"/>
<fileset dir="${core.src.dir}" includes="core-default.xml"/>
</copy>
<echo message="OK!"/>
</target>
이 부분은... 딱 놓고 말해서 이놈이 core에 있는 java 파일들을 컴파일하는구나~ 라고만 알고 있다!
막 모르는 변수(?)들이 있다 ${ ~~ }라는 놈들이다. 맨 위에 property로 추가하자. (<project name="hadoop ~> 밑에)
<property name="build.encoding" value="ISO-8859-1"/>
<property name="PROJECT" value="${basedir}"/>
<property name="src.dir" value="${PROJECT}/src"/>
<property name="core.src.dir" value="${src.dir}/core"/>
<property name="build.dir" value="${PROJECT}/build"/>
<property name="build.classes" value="${build.dir}/classes"/>
<property name="javac.debug" value="on"/>
<property name="javac.optimize" value="on"/>
<property name="javac.deprecation" value="off"/>
<property name="javac.version" value="1.6"/>
<property name="javac.args" value=""/>
<property name="javac.args.warnings" value="-Xlint:unchecked"/>
추가하였다.
일단 컴파일을 하겠지만 그 전에 class 파일을 담고 있을 디렉터리가 필요하다. 그 과정은 target init에서 한다.
다시 compile-core-classes target 밑에(</target>) 추가한다.
<target name="init">
<echo message="init... start"/>
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.src}"/>
<mkdir dir="${build.classes}"/>
<mkdir dir="${build.webapps}/hdfs/WEB-INF"/>
<mkdir dir="${build.webapps}/datanode/WEB-INF"/>
<echo message="init... end"/>
</target>
막 모르는 변수(?)들이 있다. 위에 property로 추가하자.
<property name="build.src" value="${build.dir}/src"/>
<property name="build.webapps" value="${build.dir}/webapps"/>
지금까지 만든 build.xml의 실행을 예상해보면
1. init
2. compile-core-classes
까지 실행될 것이다. 다음으로는 compile-hdfs-classes target을 만들어보자.
init target 밑에
<target name="compile-hdfs-classes" depends="compile-core-classes">
<echo message="Compile hdfs classes ..."/>
<jsp-compile
uriroot="${src.webapps}/hdfs"
outputdir="${build.src}"
package="org.apache.hadoop.hdfs.server.namenode"
webxml="${build.webapps}/hdfs/WEB-INF/web.xml">
</jsp-compile>
<jsp-compile
uriroot="${src.webapps}/datanode"
outputdir="${build.src}"
package="org.apache.hadoop.hdfs.server.datanode"
webxml="${build.webapps}/datanode/WEB-INF/web.xml">
</jsp-compile>
<javac
encoding="${build.encoding}"
srcdir="${hdfs.src.dir};${build.src}"
includes="org/apache/hadoop/**/*.java"
destdir="${build.classes}"
debug="${javac.debug}"
optimize="${javac.optimize}"
target="${javac.version}"
source="${javac.version}"
deprecation="${javac.deprecation}">
<compilerarg line="${javac.args} ${javac.args.warnings}"/>
<classpath refid="classpath"/>
</javac>
<copy todir="${build.classes}">
<fileset dir="${hdfs.src.dir}" includes="**/*.properties"/>
<fileset dir="${hdfs.src.dir}" includes="hdfs-default.xml"/>
</copy>
<echo message="OK!"/>
</target>
을 추가한다. 모르는 변수(?)들이 있다. 위에 property로 추가하자.
<property name="src.webapps" value="${basedir}/src/webapps"/>
<property name="hdfs.src.dir" value="${src.dir}/hdfs"/>
끝! 이 아니다! classpath를 설정해야 한다. 아무 대다 해도 상관없지만 깔끔해 보이기 위해 property 아래에다가 추가한다.
<path id="project.classpath">
<fileset dir="${PROJECT}/lib" includes="**/*.jar" />
</path>
<path id="classpath">
<pathelement location="${build.classes}"/>
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
<exclude name="**/excluded/"/>
</fileset>
<pathelement location="${conf.dir}"/>
</path>
<path id="test.classpath">
<pathelement location="${test.build.extraconf}"/>
<pathelement location="${test.build.classes}"/>
<pathelement location="$[test.src.dir}"/>
<pathelement location="${build.dir}"/>
<fileset dir="${test.lib.dir}">
<include name="**/*.jar"/>
<exclude name="**/excluded"/>
</fileset>
<path refid="classpath"/>
</path>
변수(?)도 추가하고!
<property name="lib.dir" value="${basedir}/lib"/>
<property name="test.build.dir" value="${build.dir}/test"/>
<property name="test.build.extraconf" value="${test.build.dir}/extraconf"/>
<property name="test.build.classes" value="${test.build.dir}/classes"/>
<property name="test.src.dir" value="${basedir}/src/test"/>
<property name="test.lib.dir" value="${basedir}/src/test/lib"/>
<property name="conf.dir" value="${basedir}/conf"/>
그다음 ! JAR 파일을 만들기 위한 target을 맨 마지막에 추가한다. (</project> 위에)
<target name="jar" depends="compile" description="Make hadoop.jar">
<tar compression="gzip" destfile="${build.classes}/bin.tgz">
<tarfileset dir="bin" mode="755"/>
</tar>
<jar jarfile="${build.dir}/${final.name}-core.jar"
basedir="${build.classes}">
<manifest>
<section name="org/apache/hadoop">
<attribute name="Implementation-Title" value="Hadoop"/>
<attribute name="Implementation-Version" value="${version}"/>
<attribute name="Implementation-Vendor" value="Apache"/>
</section>
</manifest>
<fileset file="${conf.dir}/commons-logging.properties"/>
<fileset file="${conf.dir}/log4j.properties"/>
<fileset file="${conf.dir}/hadoop-metrics.properties"/>
<zipfileset dir="${build.webapps}" prefix="webapps"/>
</jar>
</target>
변수(?)도 추가하고!
<property name="name" value="hadoop"/>
<property name="version" value="0.20.3-dev"/>
<property name="final.name" value="${name}-${version}"/>
build.xml에서 해줄 수 있는 건 모두 끝났다. 이제 :wq로 vim을 종료한 후 ant jar을 해보자!
오류가 빡! 날 것이다! 어떤 오류냐면 compile 중 어떤 class를 찾을 수 없다고 나올 것이다.
이것은 우리가 전 포스터에서 hdfs와 mapreduce를 나누는 작업을 했는데. 그 작업은 프로그램 실행 시 필요한 class만 추가한 것이고 컴파일에 필요한 class는 추가한 것이 아니다. 고로 compile에 필요한 class들을 가져와야 된다.
간단하다. 윈도우 탐색기에다가 해당 class 명을 검색한다. 그러면 그 class 이름의 .java 파일이 있을 것이다. 그 파일을 실제 하둡 디렉터리 안의 위치와 같게 복사, 붙여 넣기를 한다. 그렇게 하나씩 오류가 나는 class들을 추가하다 보면 오류 없이 BUILD SUCCESSFUL이라는 말과 build 디렉터리 안에 hadoop-{version}-dev-core.jar 라는 파일이 생겨있을 것이다.
hadoop의 설정인 conf 디렉터리를 옮겨와 싱글모드로 설정하고 bin 디렉터리도 옮겨와 hdfs를 실행시켜보자
bin/start-dfs.sh
명령이 실행되면 logs 디렉터리도 생성되고 jps 명령을 치면 namenode, datanode, secondarynamenode 가 실행되어 있을 것이다. 이렇게 hdfs와 mapreduce를 분리하여 컴파일해보았다.
XML을 이렇게 대충 필요한 것만 뽑아서 만들어 보았다.
물론 test version이니까 이렇게 대충해도 되지만. 나중에 수정하여 배포용으로 compile 할 때는 XML을 공부하고 좀 더 깔끔하게 만들어야겠다.