주요글: 도커 시작하기
반응형
자바및 XML 기반의 빌드 툴인 Ant에 대해서 살펴본다.

Ant!

유닉스/리눅스 시스템에서 C나 C++로 프로그래밍을 해본 개발자라면 make라는 프로그램에 대해서 알 것이다. make는 makefile 이라는 설정 파일을 기반으로 소스 코드를 컴파일 해 주고 컴파일된 오브젝트 코드를 모아서 실행 가능한 코드로 만들어주는 등의 많은 작업들을 한번의 배치성 작업으로 처리할 수 있도록 해 주는 프로그램이다. 자바의 경우도 자바 소스 코드를 컴파일해주고, 컴파일된 클래스 파일을 배포본으로 변경해주고 그리고 소스 코드로부터 API 문서를 생성하는 작업을 한번의 배치 작업으로 처리할 수 있도록 해주는 프로그램이 있다. 그것은 Tomcat으로 유명한 아파치의 자카르타 프로젝트에서 진행되고 있는 Ant라는 것이다.

Ant는 자바 기반의 빌드툴로서 make와 비슷한 기능을 제공하고 있다. 하지만 Ant는 다음과 같은 면에서 make와 같은 쉘기반의 빌드툴과는 다르다.

  • Ant는 자바기반이기 때문에 플랫폼에 독립적으로 실행된다.
  • 복잡할 쉘 명령어 대신에 XML 기반의 설정 파일을 사용하기 때문에 작업을 설정하는 것이 복잡하지 않다.
  • 미리 정의된 태스크(Task)를 사용하여 매우 쉽고 빠르게 배치 작업을 설정할 수 있다.
  • 새로운 태스크의 추가를 통해서 처리 가능한 배치 작업의 확장이 가능하다.
비록 쉘 스크립트를 기반으로 할 경우 몇몇의 강력한 표현기능을 사용할 수 있다는 장점이 있지만, Ant는 그 몇몇 강력한 표현기능을 잃는 대신 보다 많은 장점을 얻게 되었다. 또한 플랫폼에 독립적이기 때문에 개발자들은 어느 운영체제에서건 같은 프로젝트를 진행할 수 있게 되며, 쉘 스크립트와 비교할 수 없을 정도로 간단한 XML 기반의 빌드 설정 파일을 사용하여 미리 정의된 빌트인 태스크(Task)를 설정함으로써 매우 간단하고 쉽게 배치 작업을 지정할 수 있도록 해 준다. 태스크는 Ant를 통해서 처리하고자 하는 작업을 나타내는 것으로서 파일을 복사하는 태스크, 소스 코드를 컴파일하는 태스크, Javadoc API를 생성해주는 태스크 등 다양한 태스크가 미리 정의되어 있다.

Ant의 설치

Ant를 사용하려면 먼저 Ant를 컴퓨터에 설치해야 한다. Ant는 자카르타의 홈페이지인 http://jakarta.apache.org에서 구할 수 있다. 현재 Ant는 1.4 버전이 출시된 상태이며 자카르타의 다른 프로젝트들과 마찬가지로 바이너리와 소스의 두 가지 형태의 배포본을 제공하고 있다. 이 두 가지 배포본 중 바이너리 배포본은 설치하는 데 큰 어려움이 없으므로 바이너리 배포본을 설치하는 것에 대해서 살펴보도록 하자.

바이너리 배포본은 현재 윈도우즈 배포본인 jakarta-ant-1.4-bin.zip과 유닉스/리눅스 배포본인 jakarta-ant-1.4-bin.tar.gz의 두 파일이 있다. 이 두 파일은 실제 내용은 같다. 운영체제에 따라 알맞은 파일을 다운로드 받은 후 알맞은 디렉토리에 압축을 풀도록 하자. 필자의 경우 윈도우즈 시스템의 C:\에 jakarta-ant-1.4-bin.zip 파일의 압축을 풀어서 사용하고 있다.

c:\에 바이너리 배포본의 압축을 풀면 다음 표1과 같은 디렉토리가 생성될 것이다.

디렉토리 설명
C:\jakarta-ant-1.4 Ant 1.4의 홈 디렉토리
C:\jakarta-ant-1.4\bin Ant 1.4의 실행 파일
C:\jakarta-ant-1.4\docs Ant 1.4의 문서 파일. 사용자 매뉴얼과 FAQ 문서 등을 포함하고 있다.
C:\jakarta-ant-1.4\lib Ant 1.4의 핵심 패키지를 비롯하여 XML 파서 등 Ant를 실행하는 데 필요한 클래스 라이브러리를 포함하고 있다.

환경변수 설정


Ant의 설치가 완료되었다면, Ant가 올바르게 실행되도록 환경변수를 지정해주어야 한다. 환경 변수는 다음과 같이 지정해주면 된다.

  • Ant를 실행할 수 있도록 [Ant 홈]\bin 디렉토리를 PATH 환경변수에 추가한다.
  • 환경변수 ANT_HOME의 값을 Ant의 홈디렉토리로 지정한다.
  • 환변변수 JAVA_HOME의 값을 Java의 홈디렉토리로 지정한다.
예를 들어, Ant의 홈디렉토리가 c:\ant라고 할 경우 윈도우즈에서는 다음과 같이 환경 변수를 지정해주면 된다.

  set ANT_HOME=c:\ant
  set JAVA_HOME=c:\jdk1.2.2
  set PATH=%PATH%;%ANT_HOME%\bin

그리고 유닉스나 리눅스 시스템일 경우에는 다음과 같이 지정해주면 된다.

  export ANT_HOME=/usr/local/ant
  export JAVA_HOME=/usr/local/jdk-1.2.2
  export PATH=${PATH}:${ANT_HOME}/bin

이 중 JAVA_HOME 환경변수는 선택사항이며 필수사항은 아니다. JAVA_HOME 환경변수는 몇몇 특수한 태스크를 사용하는 경우에만 지정해주면 되며 일반적인 경우에는 지정해주지 않아도 무방하다.

윈도우즈 98이나 95를 사용할 경우 ANT_HOME 디렉토리 이름이 길 경우 운영체제의 제한 때문에 Ant의 실행파일인 ant.bat 파일이 제대로 실행되지 않게 된다. 따라서 윈도우즈 98이나 95를 사용할 경우에는 ANT_HOME 디렉토리의 이름을 jakarta-ant-1.4가 아닌 ant와 같이 짧은 이름으로 변경해주기 바란다.

Ant의 실행

Ant의 실행은 매우 간단하다. 앞에서 설명한 환경변수를 올바르게 설정하였다면 단순히 커맨드 프롬프트에서 다음과 같이 입력하면 된다.

  c:\myproject>ant

ant.bat(또는 ant.sh)을 실행하면 Ant의 설정 파일인 build.xml 파일을 현재 디렉토리부터 시작해서 상위 디렉토리로 이동해가면서 검색하게 된다. build.xml 파일이 발견되면 Ant는 build.xml 파일을 분석하여 build.xml 파일에 정의되어 있는 태스크에 따라 알맞은 배치 작업을 수행한다.

단순히 위와 같이 'ant'만 입력해도 Ant가 실행되지만, ant는 개발자가 명령어 프롬프트에서 옵션을 입력해서 여러 내용들을 직접 설정할 수 있도록 하고 있다. ant는 기본적으로 다음과 같은 형태로 명령행 인자를 입력받는다.

  ant [옵션] [타겟 [타겟2 [타겟3] ...]]

여기서 [옵션]에는 빌드 파일, 로그 파일 그리고 프로퍼티 등의 값을 지정할 수 있는 옵션이 오게 되며 [타겟]에는 빌드 파일에 지정되어 있는 <target> 태그의 name 속성의 값이 온다. [타겟]을 지정하지 않을 경우 빌드 파일에서 <project> 태그의 default 속성의 값을 작업 대상으로 사용한다. 이에 대한 내용은 <project> 태그와 <target> 태그를 설명할 때 보다 자세히 살펴보기로 하자.

표2는 Ant를 실행할 때 사용할 수 있는 주요 옵션 목록이다.

옵션 설명
-help 도움말을 출력한다.
-projecthelp 프로젝트의 도움말 정보를 출력한다.
-version 버전 정보를 출력한다.
-quiet 적은 양의 메시지를 출력한다.
-verbose 추가적인 메시지를 출력한다.
-debug 디버깅 정보를 출력한다.
-logfile file 로그 메시지를 file에 기록한다.
-buildfile file 지정한 file을 빌드 파일로 사용한다.
-Dproperty=value 이름이 property인 프로퍼티의 값을 value로 지정한다.

예를 들어, 빌드 파일로 build.xml이 아닌 testbuild.xml을 사용하고 작업 대상(target)을 main으로 하고 싶다면 다음과 같이 실행하면 된다. (작업 대상에 대한 내용은 잠시 뒤에 살펴볼 것이다.)

  ant -buildfile testbuild.xml main

표2에서 설명한 옵션 외에도 몇몇 옵션이 더 있는데, 이 옵션은 -help 옵션을 사용하여 확인할 수 있다.

Ant의 사용

make를 사용하기 위해서 makefile을 알맞게 작성해야 하듯이 Ant를 올바르게 활용하기 위해서는 Ant가 사용할 빌드 파일을 알맞게 작성해야만 한다. Ant의 빌드 파일은 XML 문서의 구조를 갖고 있으며 Ant가 작업을 수행할 프로젝트에 대한 정보를 담고 있으며, 다음과 같은 형태를 취하고 있다.

  <project name="프로젝트이름" default="기본타겟이름" basedir="." >
    
    <target name="타겟이름">
      <property name="프로퍼티이름1" value="프로퍼티값1"/>
      <property name="프로퍼티이름2" value="프로퍼티값2"/>
    </target>
  
    <target name="타겟이름1">
      <태스크명/>
      <태스크명1 dir="${build}"/>
      <property name="프로퍼티이름3" value="프로퍼티값3"/>
    </target>
  
    <target name="타겟이름2" depends="타겟이름1">
      <태스크명2 속성1="값1" 속성2="값2"/>
    </target>
  
  </project>

위 코드를 보면 크게 project, property, target, 태스크의 네가지 요소로 빌드 파일이 구성되어 있는 것을 알 수 있다. 위에서 '태스크명n'으로 표시된 태그는 target 태그가 나타내는 대상이 수행할 작업을 나타내는 것으로서 소스 코드를 컴파일해주는 태스크, Jar를 사용하여 압축해주는 태스크 등 다양한 종류의 태스크가 미리 개발되어 있다.

이 네 가지 요소가 Ant의 모든 기능을 사용할 수 있도록 해 주며, 네 가지 요소를 알맞게 조합함으로써 개발자는 원하는 작업을 배치 작업으로 처리할 수 있게 된다. 이 글의 나머지 부분에서는 빌드 파일에서 사용되는 project, target, property 그리고 태스크 태그를 어떻게 설정해주는지 구체적으로 살펴보도록 하자.

project

<project> 태그는 빌드 파일의 루트 태그로서 프로젝트 자체를 정의해준다. 모든 빌드 파일은 한 개의 project 태그를 가지며, project 태그는 프로젝트를 설명하기 위해서 다음과 같은 속성을 사용한다.

속성 설명 필수여부
name 프로젝트의 이름 필수아님
default ant.bat 파일을 실행할 때 [타겟]이 지정되지 않을 때 기본적으로 사용할 타겟 필수
basedir 경로 계산을 할 때 사용할 기본 디렉토리. basedir 프로퍼티를 지정했을 경우, 그 값을 이 속성에서 지정한 값으로 대체한다.만약 이 속성도 지정하지 않고 basedir 프로퍼티도 지정하지 않았을 경우에는 빌드 파일이 위치하는 디렉토리를 기본 디렉토리로 사용한다. 필수아님

Ant는 Ant를 실행할 때 가장 먼저 실행할 태스크를 지정할 수 있는 두가지 방법을 갖고 있는데, 한 가지는 앞에서 Ant 실행할 때 [타겟]을 지정해주는 것이며 다른 하나는 <project> 태그의 default 속성을 사용하여 첫번째로 실행할 태스크를 지정해주는 것이다.

default 속성의 값은 반드시 지정해주어야 하는 것으로서 Ant를 실행할 때 [타겟]을 지정해주지 않을 경우 default 속성의 값을 사용하여 첫번째로 수행할 [타겟]을 선택하게 된다.

target

<target> 태그는 <project> 태그에 포함되며, 실제로 프로젝트가 수행하게 될 작업(태스크)을 지정한다. <target> 태그의 기본 구조는 다음과 같다.

    <target name="타겟이름1">
      <태스크명/>
      <태스크명1 dir="${build}"/>
      <property name="프로퍼티이름3" value="프로퍼티값3"/>
    </target>

하나의 <project> 태그는 여러 개의 <target< 태그를 포함할 수 있으며, 각각의 <target> 태그는 그 타겟을 통해서 수행하고자 하는 태스크(작업)를 명시한다. 즉, 실제 작업의 처리는 <target> 태그 내에 명시되어 있는 태스크를 통해서 이루어지는 것이다. 이때 각각의 <target> 태그는 상호간 의존관계가 있을 수 있다. 예를 들어, 일반적인 어플리케이션의 빌드 순서는 '컴파일->API 문서생성->배포판 생성'인데, 이 경우 빌드 파일에는 이 각각의 작업에 대한 <target>이 있을 것이다. 즉, 컴파일을 위한 <target> 태그, API 문서 생성을 위한 <target> 태그 그리고 배포판 생성을 위한 <target> 태그 등 3개의 <target> 태그가 존재하게 되며 다음과 같이 빌드 파일이 구성되어 있다고 해 보자.

    <target name="compile">
      ...
    </target>

    <target name="apidoc">
      ...
    </target>

    <target name="makeproduct">
      ...
    </target>

이 때, 각각의 타겟의 수행순서는 compile 타겟, apidoc 타겟, makeproduct 타겟이어야 한다. 즉, apidoc 타겟은 compile 타겟에 의존하고 makeproduct 타겟은 apidoc 타겟에 의존하게 되는 것이다. 이러한 의존관계는 <target> 태그의 depends 속성을 통해서 지정할 수 있다. 예를 들어, 다음과 같이 depends 속성이 명시되어 있다고 해 보자.

  <target name="A"/>
  <target name="B"/>
  <target name="C"/>
  <target name="D" depends="C,B,A"/>

여기서 여러분이 최종적으로 실행하고자 타겟이 D라고 해 보자. 이 때, 타겟 D의 depends 속성의 값은 "C,B,A"인데 이는 타겟 D를 실행하기 위해서는 먼저 타겟 C, B, A가 수행되어야 함을 의미한다. 이때 타겟 C, B, A가 수행되는 순서는 depends 속성에 표시된 순서대로 수행되게 된다. 즉, 타겟 D를 실행하면 타겟 C가 먼저 실행되고, 그 다음 타겟 B, 그 다음 타겟 A, 그리고 마지막으로 타겟 D가 실행된다.

그런데, 다음과 같이 타겟 B와 타겟 C가 depends 속성을 갖고 있다고 해 보자.

  <target name="A"/>
  <target name="B" depends="A"/>
  <target name="C" depends="B"/>
  <target name="D" depends="C,B,A"/>

이 경우에는 타겟 C가 타겟 B에 의존하고 있고, 타겟 B는 타겟 A에 의존하고 있기 때문에 타겟 C가 가장 먼저 실행되기 보다는 타겟 A가 가장 먼저 실행되고, 그 다음에 타겟 B, 그 다음에 타겟 C, 그리고 마지막으로 타겟 D가 실행되게 된다. 이러한 depends 속성을 이용하여 앞의 빌드 순서를 표시한 타겟을 다시 표현하면 다음과 같이 변경된다.

    <target name="compile">
      ...
    </target>

    <target name="apidoc" depends="compile">
      ...
    </target>

    <target name="makeproduct" depends="apidoc">
      ...
    </target>

여러 개의 <target> 태그의 depends 속성이 같은 타겟의 이름을 값으로 가질 수도 있으나 이에 상관없이 각각의 타겟은 오직 한번만 실행된다.

Ant의 빌드 파일에서는 프로퍼티를 사용할 수 있는데, <target> 타겟 태그는 if 속성을 사용하여 특정한 프로퍼티가 지정되어 있을 경우에만 작업을 수행하도록 할 수 있다. 또한, unless 속성을 사용하여 프로퍼티가 지정되어 있지 않을 경우에만 작업을 수행하도록 할 수도 있다. 예를 들어, 테스트 단계와 배포판 생성 단계에서 각각 다른 태스크를 수행해야 할 경우 다음과 같이 "test" 프로퍼티를 사용할 수 있을 것이다.

    <target name="test" if="test" depends="compile" >
      ...
    </target>

    <target name="distribute" unless="test" depends="compile">
      ...
    </target>

<target> 태그는 그 타겟에 대한 설명을 description 속성을 통해서 할 수 있다. description 속성에 명시한 값은 ant.bat을 실행할 때 명령행 옵션인 -projecthelp를 통해서 볼 수 있다.

태스크

타켓이 각 수행할 작업간의 의존관계나 수행 조건 등을 표시한다면 태스크는 타켓 내에서 실제로 수행할 작업을 나타낸다. 예를 들어, 여러분은 태스크를 통해서 소스 코드를 컴파일하고 파일을 복사/삭제하고 API 문서를 생성할 수 있다. 태스크 <target> 태그에 중첩되어 표시되며 다음과 같은 구조를 갖고 있다.

  <태스크명 속성1="값1" 속성2="값2" ... />

'태스크명'은 태스크의 이름을 나타내고 '속성n'과 '값n'은 각각 태스크를 처리할 때 사용할 속성값을 나타낸다.

태스크는 이미 만들어져 있는 빌트인(built-in) 태스크를 사용할 수도 있고, 추가적으로 제공되는 옵션(optional) 태스크를 사용할 수도 있다. 또한 직접 작성한 태스크를 사용할 수도 있다. 예를 들어, 빌트인 태스크인 javac를 사용하여 소스 코드를 컴파일 할 때는 다음과 같이 <target> 태그에 javac 태스크를 중첩시키면 된다.

  <target name="compile" depends="init">
     <javac srcdir="${src}"
            destdir="${build}"
            classpath="jcorelogging.jar"  />
  </target>

위 코드에서 <javac src="${src}" ... /> 태그가 <target> 태그에 중첩되어 있는 것을 알 수 있는데, 이때 javac는 태스크명을 나타내며, srcdir과 destdir, classpath는 각각 javac 태스크에서 사용되는 속성을 나타낸다. 그리고 각 속성의 값 중, "${"로 시작하고 "}"로 끝나는 것이 있는데 이는 프로퍼티를 나타내는 것으로서 "${"와 "}" 사이에 있는 문자열의 프로퍼티의 이름이다.

property

프로젝트를 진행하다보면 다양한 프로퍼티를 사용하게 된다. 컴파일할 소스 코드의 위치, 컴파일된 클래스 파일을 저장할 디렉토리, 압축한 파일을 위치시킬 디렉토리 등 유연한 개발을 위해서는 다양한 프로퍼티의 사용이 필수적이라 할 수 있다. Ant는 이처럼 빌드 과정에서 사용되는 다양한 프로퍼티를 지정할 수 있도록 하고 있으며, 또한 몇몇 개의 빌트인 프로퍼티를 제공하고 있다.

프로퍼티의 지정은 property 태스크를 통해서 할 수 있으며, property 태스크는 표4와 같은 속성을 갖고 있다.

속성 설명 필수여부
name 설정할 프로퍼티의 이름 필수아님
value 프로퍼티의 값 name 속성을 사용할 경우 세 속성중의 하나를 지정해야 한다.
location 프로퍼티를 주어진 파일의 절대 파일명으로 지정한다. 이 속성의 값이 절대 경로일 경우, '/'나 '\'와 같은 구분자는 현재 플래폼에 알맞게 처리된다. 절대 경로가 아닐 경우 프로젝트의 basedir에 상대적인 경로로 처리된다.
refid 다른 곳에서 정의된 객체를 참조한다.
resource 프로퍼티 파일을 나타내는 자원의 이름 name 속성을 사용하지 않을 때 이 세 속성중의 한 개를 사용해야 한다.
file 프로퍼티 파일의 파일 이름
environment 환경 변수를 읽을 때 사용할 접두어. 만약 environment="myenv"라고 지정했다면, OS에 종속적인 환경변수인 PATH나 TEMP와 같은 값을 "myenv.PATH"나 "myenv.TEMP"와 같은 프로퍼티 이름을 사용하여 구할 수 있다.
classpath 자원을 검색할 때 사용할 클래스패스 필수아님
classpathref 다른 곳에서 정의된 PATH에 대한 참조로서 주어진 자원을 검색할 때 사용할 클래스패스 필수아님

예를 들어, "buildno" 속성의 값을 "356"으로 지정하고 싶다면 다음과 같이 하면 된다.

  <property name="buildno" value="356"/>

또한, 특정한 파일에 저장된 프로퍼티를 사용하고 싶다면 다음과 같이 file 속성을 사용하면 된다.

  <property file="build355.properties" />

Ant의 빌드 파일에서는 자바에서 기본적으로 제공하는 "java.version"과 같은 시스템 프로퍼티를 기본적으로 사용할 수 있으며, 추가적으로 Ant 자체에서 기본적으로 제공하는 프로퍼티를 사용할 수 있다. Ant가 기본적으로 제공하는 프로퍼티 목록은 다음표와 같다.

프로퍼티 설명
basedir 프로젝트의 기본 디렉토리에 대한 절대 경로. <project> 태그의 basedir 속성값을 사용한다.
ant.file 빌드 파일의 절대 경로
ant.version Ant의 버전
ant.project.name 현재 실행중인 프로젝트의 이름. <project> 태그의 name 속성값을 사용한다.
ant.java.version Ant가 발견한 Java의 버전

프로퍼티는 특정한 타켓에서만 사용되도록 지정할 수도 있고 전체에서 사용되도록 지정할 수도 있다. 다음 예를 살펴보자.

  <project name="MyProject" default="dist" basedir=".">
  
    <!-- 빌드를 위한 글로벌 프로퍼티 -->
    <property name="build" value="build"/>
    <property name="dist"  value="dist"/>
  
    <target name="init">
      <!-- init 타켓 내에서 프로퍼티 지정 -->
      <property name="src" value="."/>
      <mkdir dir="${build}"/>
    </target>
  
    <target name="compile" depends="init">
      <javac srcdir="${src}" destdir="${build}"/>
    </target>
  
    <target name="dist" depends="compile">
      <mkdir dir="${dist}/lib"/>
  
      <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
    </target>
  
    <target name="clean">
      <delete dir="${build}"/>
      <delete dir="${dist}"/>
    </target>
  </project>

위 빌드 파일을 보면 build, dist 프로퍼티는 프로젝트 전체에서 사용될 수 있는 프로퍼티로서 빌드 파일의 어떤 곳에서든지 사용될 수 있다. 반면에 init 타켓 내에 정의된 src 프로퍼티는 init 타켓에 직간접적으로 의존하고 있는 타켓에서만 사용될 수 있다. 위 코드에서는 init 타켓에 의존하고 있는 compile 타켓에서 src 프로퍼티를 사용할 수 있음을 알 수 있다. 또한 간접적으로 init 타겟에 의존하고 있는 dist 타겟 역시 src 프로퍼티를 사용하고 있다.

파일과 디렉토리 지정을 위한 패턴 관련 태그

어플리케이션을 빌드하는 과정에서 흔히 필요한 작업이 다음과 같은 것들이다.

  • /project/src 디렉토리 및 그 하위 디렉토리에 존재하는 모든 파일을 /dist/src 디렉토리에 복사한다. 단, /project/src 디렉토리 및 그 하위 디렉토리에서 디렉토리 이름이 'CVS' 디렉토리는 복사하지 않는다.
  • /src 디렉토리에 있는 *.java 파일을 컴파일한다. 단, Test로 시작하는 .java 파일은 컴파일하지 않는다.
  • A 디렉토리에 있는 파일은 모두 컴파일하고 B 디렉토리에 있는 파일은 컴파일하지 않는다.
위와 같은 사항은 대부분은 특정 디렉토리의 특정 파일을 처리하는 데 포함시키고, 어떤 디렉토리 또는 파일은 포함하지 않는 식의 것들이다. Ant는 이처럼 특정 파일/디렉토리를 표현할 수 있는 방법을 제공하고 있으며, 그 표현 방법을 사용하여 지정한 파일/디렉토리를 처리 대상에 포함시킬 수도 있고 처리 대상에서 삭제할 수도 있다.

특정 디렉토리/파일의 지정은 일정한 패턴을 통해서 표현된다. 패턴에서 사용되는 글자는 '*'와 '?'이다. 아마 많은 개발자들이 도스나 리눅스에서 dir이나 ls 명령어를 사용할텐데, '*'와 '?' 글자는 dir이나 ls 명령어를 입력할 때 사용되는 와일드캐릭터인 '*'와 '?'와 비슷한 의미를 지닌다. Ant의 설정 파일에서 이 두 글자는 다음과 같은 의미를 지닌다.

  • '*' - 0개 또는 그 이상의 글자가 매칭된다.
  • '?' - 한 글자와 매칭된다.
예를 들어, *.java 는 끝에가 .java로 끝나는 모든 파일을 나타낸다. 따라서 '*.java'는 'SomeClass.java'나 'A.java' 등 .java로 끝나는 모든 파일을 지정하는 것이 된다. 반면에 '?.java'는 ? 가 정확하게 한 글자에 매칭되기 때문에 'SomeClass.java'는 선택이 안 되며, 'A.java'나 'B.java'와 같이 정확하게 '?'의 개수와 일치하는 파일만이 선택된다.

디렉토리를 지정할 때도 이 두 글자를 사용할 수 있다. 예를 들어, 'mywork/src?/*/*.java'와 같이 지정했을 경우 'mywork/src1/jcore/ABC.java'나 'mywork/srcA/java/MySome.java'과 같은 파일을 지정할 수 있게 된다. 또한, 좀더 유연한 방법을 제공하기 위해 Ant는 '**'를 사용하여 디렉토리를 지정할 수 있도록 하고 있다. 디렉토리 지정에서 '*'를 사용할 경우 디렉토리 트리에서 단 하나의 계층만을 가리키게 되는 반면에 '**'는 다계층을 나타낸다. 즉, 'mywork/*/A.java'라고 하면 'mywork/some/A.java'나 'mywork/src/A.java'와 같이 '*'가 명확하게 하나의 디렉토리 레벨만을 나타내지만, 'mywork/**/A.java'라고 할 경우 'mywork/some/A.java'는 물론 'mywork/some/jcore/A.java'나 'mywork/com/javacan/test/A.java'와 같이 여러 레벨의 디렉토리를 나타내는 것이다.

'**'로 패턴이 끝나게 되면 디렉토리 뿐만 아니라 모든 파일을 나타낸다. 예를 들어, 'xyz/**' 패턴은 'xyz/A.java', 'xyz/some/A.java'를 포함하게 된다. 그리고 패턴의 마지막이 디렉토리를 구분해주는 '/'나 '\'일 경우에는 자동으로 맨 뒤에 '**'가 붙게 된다. 즉, 'xyz/' 패턴은 'xyz/**' 패턴과 동일한 의미를 지닌다.

참고사항으로, 다음 패턴들은 특별히 지정하지 않는 한 태그 또는 태스크가 처리할 파일 또는 디렉토리 패턴에서 자동으로 제외된다.

  **/*~
  **/#*#
  **/.#*
  **/%*%
  **/CVS
  **/CVS/**
  **/.cvsignore
  **/SCCS
  **/SCCS/**
  **/vssver.scc

patternset

<patternset> 태그는 패턴을 집합을 지정할 때 사용되며, 다음과 같은 구조를 갖고 있다.

  <patternset id="sources" >
    <include name="std/**/*.java"/>
    <include name="prof/**/*.java" if="professional"/>
    <exclude name="**/*Test*"/>
  </patternset>

위에서 patternset 태그의 id 속성을 지정했는데, 패턴을 사용하는 다른 태스크나 태그들은 id 속성의 값을 사용하여 patternset을 참조할 수 있게 된다. 예를 들어, 파일의 집합을 지정할 때 사용되는 fileset 태그에서 위 patternset을 참조하고 싶다면 다음과 같이 하면 된다.

  <fileset dir="${client.src}" >
    <patternset refid="sources"/>
  </fileset>

<patternset> 태그를 보면 안에 <include> 태그, <exclude> 태그가 중첩된 것을 알 수 있는데, 이 두 태그는 각각 <patternset> 태그가 포함할 패턴과 포함하지 않을 패턴을 나타낸다. 이 두 태그 뿐만 아니라 <includesfile> 태그와 <excludesfile> 태그가 존재한다. 이 네 태그는 각각 다음의 의미를 지닌다.

태그 설명
include 특정한 패턴이 나타내는 디렉토리 및 파일을 포함한다.
exclude 특정한 패턴이 나타내는 디렉토리 및 파일을 포함시키지 않는다.
includesfile 특정 파일을 포함한다.
excludesfile 특정 파일을 포함시키지 않는다.

이 네 태그는 특정 패턴 및 파일을 포함시켜야 하는 모든 태스크에도 중첩되어 사용될 수 있다. 이 네 태그는 모두 같은 속성을 갖고 있으며, 그 속성은 다음과 같다.

속성 설명 필수여부
name 패턴(include, exclude) 또는 파일(includesfile, excludesfile)의 지정 필수
if 특정 프로퍼티가 지정되어 있을 경우 수행한다. 필수아님
unless 특정 프로퍼티가 지정되어 있지 않을 경우 수행한다. 필수아님

fileset


<fileset> 태그는 파일의 집합을 나타낼 때 사용되며 <patternset> 태그를 중첩하여 파일의 집합을 표시할 수 있다. 또한 <patternset> 태그를 사용하지 않고 직접적으로 <include>나 <exclude>와 같은 태그를 사용하여 파일을 명시할 수도 있다. 예를 들어, <filest>은 다음과 같이 지정될 수 있다.

  <fileset dir="${server.src}" >
    <patternset id="non.test.sources" >
      <include name="**/*.java"/>
      <exclude name="**/*Test*"/>
    </patternset>
  </fileset>

  <fileset dir="${client.src}" >
    <patternset refid="non.test.sources"/>
  </fileset>

  <fileset dir="src/share">
    <include name="**/*.properties"/>
  </fileset>

첫번째와 두번째는 각각 <patternset>을 중첩한 예이고, 세번째는 <patternset>을 중첩하지 않고 직접적으로 <include> 태그를 사용하여 포함할 파일을 명시한 예이다. 이러한 <fileset> 태그는 javac 태스크나 javadoc 태스크와 같이 파일/디렉토리 기반의 태스크에 중첩되어 처리할 파일을 지정하는 데 사용된다. 예를 들어, Jar 파일을 생성해주는 jar 태스크에서 다음과 같이 사용될 수 있다.

  <jar jarfile="${catalina.deploy}/lib/naming-factory.jar">
    <fileset dir="${catalina.build}/classes">
      <include name="org/apache/naming/factory/**" />
      <exclude name="org/apache/naming/factory/Constants.class" />
    </fileset>
  </jar>

<fileset> 태그는 다음과 같은 속성을 제공하고 있다.

속성 설명 필수여부
dir 파일셋 디렉토리 트리의 루트 필수
defaultexcludes 기본적으로 포함되지 않는 패턴을 exclude의 요소로 사용할지의 여부(yes, no)를 지정한다. 이 속성을 지정하지 않을 경우 기본적으로 포함되지 않는 패턴을 exclude의 요소로 사용하게 된다. 필수아님
includes 포함할 파일의 패턴 목록을 지정한다. 각 패턴은 콤마로 구분한다. 생략할 경우 모든 파일을 포함한다. 필수아님
includesfile 포함할 파일명을 지정한다. 필수아님
excludes 포함하지 않을 파일의 패턴 목록을 지정한다. 각 패턴은 콤마로 구분한다. 생략할 경우 기본적으로 포함되지 않는 패턴을 제외한 모든 파일은 제외되지 않는다. 필수아님
excludesfile 포함하지 않을 파일명을 지정한다. 필수아님

앞에서 기본적으로 포함되지 않는 패턴 목록을 보여줬었는데, 만약 그 패턴들을 모두 처리하고자 한다면 <fileset> 태그의 defaultexcludes 속성의 값을 "no"라고 지정하면 된다.

주요 빌트인 태스크

주로 사용되는 빌트인 태스크에는 다음과 같은 것들이 있다.

속성 설명
Ant 현재 빌드 과정에서 또 다른 Ant 프로세스를 수행
Copydir 전체 디렉토리를 복사
Copyfile 한 파일을 복사할 때 사용
Cvs CVS 리포지토리에서 읽어온 패키지/모듈을 처리할 때 사용
Delete 파일을 삭제할 때 사용. 한 파일을 지우거나 또는 특정 디렉토리와 그 하위 디렉토리에 있는 모든 파일을 삭제할 수 있다.
Deltree 특정 디렉토리를 삭제
Exec 시스템 명령어를 실행할 때 사용.
get URL로부터 파일을 구함
jar 파일 집합을 Jar를 사용하여 압축한다.
java 현재 Ant를 실행중인 가상 머신 또는 다른 가상 머신에서 자바 클래스를 실행한다.
javac 소스 트리를 컴파일한.
javadoc (또는 javadoc2) javadoc을 사용하여 API 문서를 생성한다.
mkdir 디렉토리를 생성한다.
property 프로젝트에 사용될 프로퍼티를 지정한다.
tstamp 현재 프로젝트의 DSTAMP, TSTAMP, TODAY 프로퍼티를 지정한다.
style xslt를 사용하여 문서 집합을 처리한다.

표8에 표시한 것 중에서 property는 이미 앞에서 알아 보았으므로, 이 절에서는 가장 많이 사용되는 javac, javadoc 태스크를 사용하는 방법에 대해서 간략하게 살펴보도록 하자. Ant가 제공하는 빌트인 태스크에 대한 자세한 내용은 Ant의 사용자 매뉴얼을 참고하기 바란다.

컴파일을 위한 javac 태스크

javac 태스크는 자바 소스 코드를 컴파일할 때 사용되며, 일반적으로 다음과 같은 형태를 취한다.

  <javac srcdir="/mywork/project/src1:/mywork/project/src2"
         destdir="${build}"
         classpath="lib/mail.jar:lib/activation.jar"
         debug="on"
  />

srcdir 속성은 소스 코드를 포함하고 있는 디렉토리를 명시하는 것으로서, 여러개의 디렉토리를 지정할 수 있으며 각 디렉토리는 ':'나 ';'로 구분된다. 이때 지정한 디렉토리에 존재하는 .java 파일 뿐만 아니라 하위 디렉토리에 있는 .java 파일까지 컴파일하게 된다. srcdir 속성 대신에 <src> 태그를 중첩하여 소스 코드의 위치를 지정할 수도 있다. 예를 들어, 위 예제를 <src> 태그를 사용하여 변경하면 다음과 같이 된다.

  <proejct name="dist" default="compile" >
    <target name="compile">
      <javac destdir="${build}"
                classpath="lib/mail.jar:lib/activation.jar"
                debug="on"   >
        <src path="/mywork/project/src1">
        <src path="/mywork/project/src2">
      </javac>
    </target>
  </project>
  

destdir 속성은 컴파일한 클래스 파일을 위치시킬 디렉토리를 지정하는 것으로 지정한 디렉토리부터 컴파일한 클래스의 패키지에 알맞게 배치된다. classpath 속성은 컴파일할 때 사용할 클래스패스를 나타내며, 컴파일할 때 사용하는 CLASSPATH 환경변수나 -classpath 옵션을 지정한 것과 같은 의미를 지닌다.

srcdir 속성이나 <src> 속성에 지정한 디렉토리의 하위에 있는 소스 파일 중 일부만 컴파일하고 싶을 때는 <include> 태그와 <exclude> 태그를 사용하면 된다. 예를 들어, 기본 디렉토리를 기준으로 package/project1 디렉토리와 package/project2 디렉토리 밑에 있는 소스 코드만을 컴파일하고 싶을 때에는 다음과 같이 하면 된다.

  <javac destdir="${build}"
            classpath="lib/mail.jar:lib/activation.jar"
            debug="on"   >
    <src path="src">
    <include name="package/project1/**"/>
    <include name="package/project2/**"/>
  </javac>

이 상태에서 package/project1/test 디렉토리에 있는 소스 코드는 컴파일 목록에서 제외하고 싶다면 다음과 같이 하면 된다.

  <javac destdir="${build}"
            classpath="lib/mail.jar:lib/activation.jar"
            debug="on"   >
    <src path="src">
    <include name="package/project1/**"/>
    <include name="package/project2/**"/>
    <exclude name="package/project1/test/**"/>
  </javac>

API 문서 생성을 위한 javadoc 태스크

API 문서의 생성은 javadoc 태스크를 통해서 처리되며, 다음과 같이 사용된다.

    <javadoc packagenames="${packages}"
             sourcepath="${basedir}/${src.dir}"
             destdir="${build.javadocs}"
             author="true"
             version="true"
             windowtitle="${Name} API"
             doctitle="${Name}"
             bottom="Copyright ⓒ 2001 SomeMane. All Rights Reserved."
    />

위의 각 속성은 실제 JDK의 javadoc을 실행시켰을 때 지정해주는 명령행 인자와 유사하기 때문에 특별한 설명은 하지 않겠다. 따라서 컴파일 API 문서를 생성해주는 빌드 파일을 작성하고 싶다면 다음과 같은 형식을 취하면 될 것이다.

  <project name="build" default="api" basedir=".">
    <target name="compile">
      <javac srcdir="src" ... >
        ...
      </javac>
    </target>
    
    <target name="api" depends="compile">
      <javadoc .. >
    </target>
  
  </project>

결론

여러분은 이 글을 읽어나가면서 비록 일부분이긴 하지만 Ant의 강력함을 느꼈을 것이다. 비록 이 글에서는 javac 태스크와 javadoc 태스크만을 예로 들었지만, Ant는 이 두 태스크 분만 아니라 더욱 다양한 빌트인 태스크를 제공하고 있으며 또한 추가적으로 확장 태스크를 제공하고 있다. 이러한 태스크를 사용함으로써 개발자들은 매우 손쉽게 어플리케이션의 빌드 과정을 정의할 수 있고, 변경할 수 있고, 실행할 수 있게 되었다.

Ant가 제공하는 태스크 목록은 Ant의 사용자 매뉴얼에 나와 있으므로 Ant에 대한 보다 많은 정보를 필요로 하는 독자는 Ant 매뉴얼을 참고하기 바란다.

관련링크:

+ Recent posts