글을 적기 전 Ant카테고리를 만든 이유를 잠시 적을까 한다. Ant를 사용한 것은 지난 09년 INLIBS라는 프로젝트를 시작하면서, 빌드 자동화 및 테스트를 위해 처음 Ant를 사용하고 티스토리 블로그에 포스팅했었지만, 블로그를 이전하면서 언젠가 Ant카테고리의 데이터를 지워버렸고, 다시 Ant를 사용하려니 몇 가지 어려운 점이 있어, 다시는 잊어버리지 않기 위해 이렇게 다시 카테고리를 생성하고, Ant에 대해 Step by Step 형식으로 작성하리라 마음을 먹었다.
아무튼 Ant란 무엇일까? Ant에 대한 개인적인 생각은 매우 훌륭한 빌드 도구라는 것이다. 아마 학생이거나, 빌드라는 개념이 정확하지 않은 사람은 우선 빌드가 무엇인지 알아야 한다. 빌드란 간단하게 우리의 프로세스를 살펴보면 알 수 있다. 우리는 소스 코드 파일을 작성하면, 컴파일 하고, 유닛 테스트를 하거나, 패키지화, 배치 등 다양한 작업을 손 수(수작업) 하게 된다. 하지만 공장도 자동화되는 시점에 우리 개발자들이라고 “난 손으로 하는게 좋아!”라며 수작업을 즐기고 싶어하는 개발자는 아마 없을 것 이다. 이러한 개발자를 위해 Ant 빌더가 존재하는다. 간단한 XML로 Ant 문서를 제작해 컴파일, 업로드, 파일 압축 등의 다양한 작업들을 일괄적으로 처리하는 역할을 담당 한다.
실제로, Java Development With Ant (Erik Hatcher)라는 책에 보면, 왜 Ant가 뛰어난 빌드 도구 인지 설명 하고 있다. (아, 원서라서 번역에 상당한 에러가 있을 수 있다.) 먼저 Ant는 Java 컴파일러나 Jar파일을 만드는 것과 같은 로직을 별도의 JVM에서 구동하는 것이 아니라, Ant자체의 JVM상에서 실행하므로, 매우 빠르다. 또한, Java를 사용하여 확장이 가능하고, FTP, 텔넷, SQL 등의 명령어를 배치 자동화에 사용할 수 있다라는 것을 큰 장점으로 설명하고 있다.
사실 이보다는 Ant의 핵심 컨셉이 중요한데, 우선 Ant는 매우 간경하고, 이해하기 쉬우며, 확장성이 뛰어나다. 이런 이야기는 아직 크게 이해하기 힘든 부분일 수도 있지만, 아마 이 포스팅이 10개 정도 작성된 후 부터는 Ant가 매우 편리하다라는 생각을 누구나 하게 될 것이다.
아무튼 이렇게 긴 글들은(웅장한 설명들…) 위키피디아에 가보면 수많은 글들이 아주 멋지게 작성되어 있으므로, 이쯤에서 생략하기로 하고 실제 하나의 프로젝트를 만들고 Ant를 통해 빌드하는 작업을 첫 번째 핵심 주제로 다루어보려 한다. 우선 몇 가지 확인해야 할 것이 있는데, Ant가 정상적으로 동작하는지 알아야봐야 한다는 것이다. 당연한 소리일 수 도 있지만, 실제로 소스파일을 만들어 둔 후 Ant가 실행되지 않아서, 빌드를 하지 못했던 기억이 있기 때문에 가장 먼저 다루는 것이니 양해해주기 바란다.
우선 터미널을 실행시키고, ant -version이라는 명령어를 입력해본다. 정상적으로 구동된다면 Apache Ant version 1.8.1 compiled on September 21 2010 (뭐 버전은 다를 수도 있다만)와 같은 문구가 출력되고, 설치가 되어 있지 않다면, ‘ant’는 내부 또는 외부 어쩌고 저쩌고라는 문구가 출력된다.
정상적으로 출력된다고 가정하에 본격적으로 Ant를 사용해볼 수 있는데, 추후에 본인 스스로도 다시 이 포스팅을 읽어야 할 것이기 때문에 최대한 간단하고 쉬운 예로 포스팅을 작성하려 한다. 아래와 같은 Java 소스파일을 하나 만들어 보자.(파일의 내용은 이 글을 읽는 사용자들의 코드여도 관계 없다.)
1 2 3 4 5 6 7 | public class Main { public static void main(String [] ar) { for ( int i = 0 ; i < 5 ; i++){ System.out.println( "hello, Kim eunseok" ); } } } |
위 코드를 해석할 수 없다면, 지금 Ant를 볼 것이 아니라, Java를 봐야한다.(물론, 농담이다.) 아무튼 위와 같은 코드를 작성했다면 이제 컴파일을 담당하는 간단한 Ant문서를 작성해보도록 하자. 아! 이 예는 그렇게 권하고 싶은 예는 아니지만, 아무튼 Step by Step이라는 주제이므로, 아마 처음 Ant를 사용한 개발자라면 꽤나 편하게 사용할 수 있는 예이기도 하니 한번 작성해보도록 하겠다. ant는 xml로 작성된다고 위에서 설명했다.
1 2 3 4 5 6 7 | <? xml version = "1.0" ?> < PROJECT default = "compile" name = "build" > < TARGET name = "compile" > < JAVAC srcdir = "." /> < ECHO >Kimeunseok:Compile Test!</ ECHO > </ TARGET > </ PROJECT > |
1 | |
그리고, 작성한 xml파일을 build.xml이라고 저장하고, 위에서 작성한 Java 소스파일이 있는 디렉토리에 저장한 후 다시 터미널을 실행시켜서 위 디렉토리(Main.Java와 Build.xml,파일이 있는 디렉토리)로 이동하여, ant 라는 명령어를 실행하면 컴파일이 성공적으로 진행될 것이다. 그런데 여기서 혹시 아래와 같은 문제가 발생하는 경우도 있다.
$ ant Buildfile: build.xml compile: [javac] build.xml:4: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds [javac] Compiling 1 source file [echo] Kimeunseok:Compile Test! BUILD SUCCESSFUL Total time: 0 seconds
이 경우 build.xml 중 javac 엘리먼트에 includeantruntime=”false”를 추가해주면 되는데, 수정한 파일은 아래와 같은 코드로 작성되어 있다.
1 2 3 4 5 6 7 | <? xml version = "1.0" ?> < PROJECT default = "compile" name = "build" > < TARGET name = "compile" > < JAVAC srcdir = "." includeantruntime = "false" /> < ECHO >Kimeunseok:Compile Test!</ ECHO > </ TARGET > </ PROJECT > |
그 후 java Main을 실행해보면 정상적으로 컴파일 되었다는 것을 확인 할 수 있다. 비록 간단한 예였지만, 실제로 컴파일하고 성공했다는 메세지까지 출력해주고 있다. 물론 이것이 ant의 전부는 절대 아니다. 이제 막 커튼(요즘 부쩍 시적 표현이 늘었다…갠적인 생각.)을 열고 햇빛을 받을 준비를 한 것 뿐이고, 다음 포스팅 부터 본격적인 구조화, 자동화 등 Ant의 다양한 기능을 소개하고, 같이 해보는 시간을 가지도록 하겠다
Buildfile: build.xml compile: [echo] Kimeunseok:Compile Test! BUILD SUCCESSFUL Total time: 0 seconds
위와 같이 추가 후 다시 실행을 해보면 아래와 같이 정상적인 컴파일과 함께 컴파일이 성공했다는 echo 메세지를 출력해준다.
출처 - http://kimeunseok.com/archives/188
Step by Step : Ant Structured.
이전 포스팅을 실행 한 후 해당 디렉토리를 열어보면, 소스 파일, 클래스 파일, 빌드 파일 모두 같은 디렉토리에 들어있다보니, 파일 관리하기도 불편하다고 느끼게 될 것이고, 이전에 제작한 빌드 파일이 상당히 불편하다는 느낌을 받을 수 있다. 아마 소스 파일이 10개만 넘어가도 이제는 관리하기 힘들다는 마음이 들고 그 순간 “아, Ant를 사용하지 않는게 좋겠다”라는 생각이 들 수도 있다. 이는 이전 포스팅만을 사용했을 때 발생하는 고민이고, 이제 빌드를 구조화하여 보다 편리한 Ant빌드를 만드는 방법을 포스팅하려 한다.
우선 Ant를 구조화 하는 이유가 궁금할텐데, 가장 큰 이유는 어디서나 “위험요소를 최소화하고 깔끔한 소스 파일과 생성된 파일을 관리하기 위함”이라고 설명하거 있다. 이를 클린 빌드라고 하는데, 클린 빌드는 이전에 생성된 파일을 지우고 다시 빌드하는 것을 의미한다. 그러기 위해서는 먼저 디렉토리 자체 레이아웃을 조금 설정해야하는데 큰 규칙은 없지만, 관습상 총 4개의 디렉토리를 생성하고, 해당 구조는 아래와 같이 배치된다.
위에서 src는 소스 파일들을 모아둔 디렉토리고, build의 경우 빌드된 클래스 파일들, dist는 배포본을 저장하는 공간이라고 가정하도록 하겠다. Ant를 사용하는 거의 모든 사람들(갠적 생각)은 위와 같이 디렉토리 레이아웃이 아닌가 한다. 우선 이전 포스팅에서 만들었던 Main.java파일을 src폴더로 이동하도록 한다. 다음으로 build 디렉토리 레이아웃 설정 부분인데 본인의 경우 class를 따로 모아두기 위해 classes라는 하위 디렉토리를 생성하기로 했다. 마지막으로 dist 디렉토리에는 배포파일(예를 들면 jar과 같은)을 저장할 것이니 별도의 레이아웃 설정 없이 디렉토리 그대로를 사용하기로 한다.
이렇게 모든 디렉토리 레이아웃을 설정했다면, 이제 빌드파일을 생성해야 한다.이전의 경우 해당 디렉토리의 모든 java파일을 컴파일하므로 지금의 구조화된 빌드를 하기 위해서는 새로 빌드를 작성하는 것은 어쩌면 당연한 일이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <? xml version = "1.0" ?> < PROJECT default = "archive" name = "build" > < TARGET name = "init" > < MKDIR /> < MKDIR /> </ TARGET > < TARGET name = "compile" depends = "init" > < JAVAC srcdir = "src" includeantruntime = "false" destdir = "build/classes" /> </ TARGET > < TARGET name = "archive" depends = "compile" > < JAR basedir = "build/classes" destfile = "dist/test.jar" /> </ TARGET > < TARGET name = "clean" depends = "init" > < DELETE /> </ TARGET > </ PROJECT > |
이번에는 위 xml의 설명이 필요할지 모르겠다. 우선 코드 자체는 어렵지 않다. mkdir은 디렉토리를 생성하는 것이고, destdir의 경우 결과물을 저장할 디렉토리를 설정한다. 그리고 destfile은 배포본(jar)파일의 디렉토리와 이름을 지정하고, basedir은 배포하기 위한 클래스 파일들이 있는 위치며, delete를 통해 디렉토리를 삭제한다. 이 부분은 사실 모든 것이 영단어로 구성되어 있어 어렵지 않게 이해할 수 있지만, 여기서 가장 중요한 내용은 타겟 간의 종속성이다.
타겟 간의 종속성은 Ant가 타겟을 실행 할 때 배포본을 생성하기까지 올바른 순서로 처리할 수 있도록 설정하는 부분이라고 할 수 있다. 즉, 위의 종속구조를 보자면 아래와 같이 구성할 수 있다.
결국 위 구조를 Ant가 실행하기 위해서는 compile하기 앞서 init를 실행해야 하고, archive를 하기 위해서는 compile을 거쳐야 한다는 의미가 된다. 또한 이렇게 구조화 된 빌드의 경우 직접 타겟을 선택하여 Ant를 실행할 수 도 있는데 앞서 말한 것 처럼 현재 구조는 종속성을 가지고 있으므로, ant compile을 한다고 가정했을 때 반드시 init을 실행한다. 이를 확인하기 위해서 실제로 $ant compile을 실행해보면 아래와 같은 결과를 출력한다.
Buildfile: build.xml init: compile: BUILD SUCCESSFUL Total time: 0 seconds
즉, 위를 통해 종속관계를 적용할 경우 어떻게 ant에서 처리하는지 알수있다. 또 추가적으로 -verbose 라는 옵션을 추가하면, Ant가 어떻게 동작하는지 상세하게 확인 할 수 있다. 만약 다수의 타겟을 실행하고 싶다면,(어쩌면 벌써 파악했는지도 모르지만…)ant compile clean과 같은 방식으로 사용할 수 있다. 그 결과는 아래와 같다.
Buildfile: build.xml init: compile: init: clean: [delete] Deleting directory /dist BUILD SUCCESSFUL Total time: 0 seconds
이제 점점 Ant 빌드가 재미있어지고, 편리해지기 시작했지만, 아직 시작에 불과하다. 다음 포스팅에는 Ant에서 직접 파일을 실행하는 방법을 포스팅할까 하는데, 현재 공부하고 있는 내용이 꽤나…많아서…언제쯤 포스팅할지 모르겠지만, 아무튼 곧! 빠르게! Ant 빌드에 대한 내용을 업데이트 할 계획이니 많은 관심을 바란다.
add. 시간이 있어, 타겟으로 직접 프로그램을 실행하는 Ant빌드 파일을 만들어볼까합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <? xml version = "1.0" ?> < PROJECT default = "archive" name = "build" > < TARGET name = "init" > < MKDIR /> < MKDIR /> </ TARGET > < TARGET name = "compile" depends = "init" > < JAVAC srcdir = "src" includeantruntime = "false" destdir = "build/classes" /> </ TARGET > < TARGET name = "archive" depends = "compile" > < JAR basedir = "build/classes" destfile = "dist/test.jar" /> </ TARGET > < TARGET name = "clean" depends = "init" > < DELETE /> </ TARGET > < TARGET name = "execute" depends = "compile" > < JAVA classpath = "build/classes" classname = "Main" /> </ TARGET > </ PROJECT > |
execute는 build/classes를 classpath로 하여, Main 클래스를 실행한다. 이 빌드를 통해 $ant execute를 실행하게 되면, compile에 종속적이므로, 컴파일이 실행되고, 또 컴파일은 init에 종속적이므로 init 역시 실행된다. 정상적으로 실행이 되었다면, 콘솔창에 아래와 같은 결과가 출력된다.
Buildfile: build.xml init: [mkdir] Created dir: dist compile: execute: [java] hello, Kim eunseok [java] hello, Kim eunseok [java] hello, Kim eunseok [java] hello, Kim eunseok [java] hello, Kim eunseok BUILD SUCCESSFUL Total time: 0 seconds
출처 - http://kimeunseok.com/archives/190
'IDE & Build > Ant' 카테고리의 다른 글
Ant 소개 (0) | 2012.11.06 |
---|---|
Apache Ant (0) | 2012.03.03 |