Gradle을 이용하여 Java 프로젝트 빌드하기

이 가이드는 Gradle을 이용하여 간단한 자바 프로젝트를 빌드하는 과정을 정리한 문서입니다. 기본적으로 맥 환경에서 진행되므로 윈도우에서는 조금 다를 수 있습니다.

Homebrew를 이용하여 gradle 설치

Homebrew를 이용하면 Gradle의 설치가 정말 간단합니다. 다음의 명령어를 사용하여 설치를 합니다.

$ brew update
$ brew install gradle

설치가 완료되면 실행을 한번 해보겠습니다. 환영 메시지를 볼 수 있습니다.

$ gradle
:help

Welcome to Gradle 1.10.

To run a build, run gradle <task> ...

To see a list of available tasks, run gradle tasks

To see a list of command-line options, run gradle --help

BUILD SUCCESSFUL

Total time: 4.167 secs

샘플 어플리케이션 제작

Gradle을 이용한 빌드를 해보기 위한 샘플 자바 어플리케이션을 제작해 보겠습니다. Gradle이 이 글의 주인공이기에 프로젝트의 코드는 정말 단순합니다. 적당한 위치(저는 hello디렉토리를 생성하고 그 안에서 작업을 하였습니다)의 디렉토리 안에서 mkdir -p src/main/java/hello 를 사용하여 필요한 디렉토리 구조를 한번에 생성합니다. 다음과 같은 디렉토리 구조가 생성됩니다.

└── src
    └── main
        └── java
            └── hello

이제 src/main/java/hello 디렉토리 안에 원하는 자바 클래스 파일을 생성하면 됩니다. 하지만 정말 간단한 형태의 HelloWorld.javaGreeter.java 클래스를 생성해 보도록 하겠습니다.

package hello;

public class HelloWorld {
  public static void main(String[] args) {
    Greeter greeter = new Greeter();
    System.out.println(greeter.sayHello());
  }
}
package hello;

public class Greeter {
  public String sayHello() {
    return "Hello world!";
  }
}

Gradle로 무엇을 할 수 있는지 확인

Gradle이 정상적으로 설치 되었고 샘플 프로젝트가 준비되었습니다. 프로젝트를 위한 build.gradle 파일을 생성하기 이전에 어떤 태스크를 수행할 수 있는지 확인해 볼 수 있습니다. build.gradle 파일이 없는 폴더에서 Gradle을 실행 하였기에 매우 기본적인 태스크들만을 확인할 수 있습니다.

$ gradle tasks
:tasks

------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------

Build Setup tasks
-----------------
init - Initializes a new Gradle build. [incubating]
wrapper - Generates Gradle wrapper files. [incubating]

Help tasks
----------
dependencies - Displays all dependencies declared in root project 'hello'.
dependencyInsight - Displays the insight into a specific dependency in root project 'hello'.
help - Displays a help message
projects - Displays the sub-projects of root project 'hello'.
properties - Displays the properties of root project 'hello'.
tasks - Displays the tasks runnable from root project 'hello'.

To see all tasks and more detail, run with --all.

BUILD SUCCESSFUL

Total time: 1.927 secs

위와 같은 명령들이 수행 가능하다고 표시는 되지만 빌드 설정 파일이 없이는 실제로 할 수 있는것이 거의 없습니다. 몇몇 태스크는 build.gradle 같은 파일을 정의됨으로써 더 유용해 질 수 있습니다. build.gradle 설정에 플러그인을 추가할때마다 태스크는 점점 늘어나게 됩니다. 그러므로 프로젝트의 진행중에 가끔씩 tasks 명령을 수행하여 어떤 태스크가 수행가능한지 확인해봅시다. 다음은 이러한 플러그인중에 Java 빌드 기능을 활성화 하는 플러그인을 추가하는 과정을 진행하겠습니다.

Java 코드 빌드

매우 심플하고 기본적인 한줄짜리 build.gradle 파일을 생성해 봅시다.

apply plugin: 'java'

한줄짜리 빌드 설정이지만 매우 파워풀한 변화를 가져옵니다. gradle tasks 를 다시 실행해 봅니다. 프로젝트를 빌드하고 JavaDoc을 생성하고 테스트를 실행할 있는 태스크를 포함하여 새로운 태스크가 리스트에 추가된것을 볼 수 있습니다.

이제 gradle tasks 를 자주 실행하게 될것입니다. 이 태스크는 코드를 컴파일하고 테스트하고 조립하여 JAR 파일을 생성합니다. 다음과 같이 실행을 해봅시다.

$ gradle build

몇초의 시간이 지난뒤에 빌드가 완료되었음을 알리는 “BUILD SUCCESSFUL”이 출력됩니다. 빌드의 결과물을 확인하기 위하여 새롭게 생성된 build 디렉토리를 확인해볼 필요가 있습니다. 그 안에서 다음의 중요한 3가지 디렉토리를 포함하여 몇몇 디렉토리를 확인할 수 있습니다.

  • classes : 프로젝트의 컴파일된 .class 파일
  • reports : 빌드에 의해 생성된 레포트가 존재 (test에 대한 수행 결과)
  • libs : 조립된 프로젝트 라이브러리 파일

classes 디렉토리안에는 Java 코드로 부터 컴파일된 .class 파일이 존재합니다. 여기서는 HelloWorld.classGreeter.class 가 존재할 것입니다. 여기서 프로젝트는 어떤 라이브러리 의존성을 가지고 있지 않습니다. 그러므로 dependency_cache 디렉토리안에 아무것도 존재하지 않게됩니다.

report 디렉토리에는 프로젝트의 유닛 테스트 결과를 포함합니다. 하지만 지금은 어떤 테스트도 존재하지 않기에 확인해볼 필요는 없을것 같습니다.

libs 디렉토리는 프로젝트의 폴더 이름을 띈 JAR 파일이 만들어집니다.

의존성 선언

이 심플한 프로젝트에서는 사실 그 어떤 추가적인 라이브러리도 필요로 하지 않습니다. 하지만 대부분의 어플리케이션들은 외부의 다양한 라이브러리들의 일반적인 또는 복잡한 기능들에 의존성을 가지고 있습니다.

예시를 위해 “Hello World!” 이외에 추가적으로 현재 날짜와 시간을 출력하도록 하겠습니다. 네이티브 Java 라이브러리를 이용해서 충분히 이러한 기능을 구현할 수 있지만 우리는 외부라이브러리인 Joda Time 라이브러리를 사용하도록 하겠습니다. 첫번째로 HelloWorld.java는 다음과 같이 수정하였습니다.

package hello;

import org.joda.time.LocalTime;

public class HelloWorld {
  public static void main(String[] args) {
    LocalTime currentTime = new LocalTime();
    System.out.println("The current local time is: " + currentTime);

    Greeter greeter = new Greeter();
    System.out.println(greeter.sayHello());
  }
}

이제 HelloWorld는 Joda Time의 LocalTime 클래스를 이용하여 현재 시간을 출력하도록 변경되었습니다. 이 시점에서 gradle build를 수행한다면 빌드는 실패하게 됩니다. 왜냐하면 아직 Joda Time이 빌드의 컴파일 의존성 설정이 안되어있기 때문입니다. build.gradle에 다음을 추가함으로써 이 문제를 해결할 수 있습니다.

repositories { mavenCentral() }
dependencies {
  compile "joda-time:joda-time:2.2"
}

첫번째줄은 빌드의 의존성 해결을 위해 Maven 중앙 저장소를 활용할것을 선언하는 부분입니다. Gradle은 메이븐중앙저장소를 의존성 라이브러리로 활용하는등 많은 문법과 기능들이 Maven 빌드툴로부터 물려받았습니다.

dependencies 블록에서는 Jodat TIme에 대한 의존성 선언을 하였습니다. (오른쪽에서 왼쪽으로 읽었을 때) 이 문장은 버전 2.2의 joda-time 라이브러리를 joda-time 그룹에서 찾겠다는것을 의미합니다.

의존성 설정중에 또다른 유심히 볼 부분은 compile 입니다. 이는 해당 의존성 라이브러리가 컴파일 시점에 사용되어짐을 의미합니다. (만약 WAR 파일을 빌드한다면 /WEB-INF/libs 폴더가 포함) 다른 의존성 타입은 다음이 있습니다.

  • providedCompile : 프로젝트의 코드가 컴파일되는데 필요로 되는 의존성 라이브러리를 정의합니다. 단 실제 런타임시에 컨테이너로부터 제공받기 때문에 빌드 결과물에 포함될 필요는 없는 라이브러리임을 뜻합니다. 예로 Java ServletAPI나 JSTL 라이브러리가 있습니다.
  • testCompile : 테스트 실행시에 필요한 의존성을 정의합니다. 하지만 실제 프로젝트의 런타임에는 사용되지 않는 라이브러리임을 뜻합니다.

이제 gradle build를 실행합니다. Gradle은 Joda Time 라이브러리를 메이븐 중앙 저장소에서 다운받아 의존성을 해결한 뒤에 성공적으로 빌드를 수행하게 됩니다.

Gradle Wrapper를 이용한 프로젝트 빌드

Gradle Wrapper는 Gradle을 이용한 빌드를 시작하기 위해 선호되는 방법입니다. 이 래퍼는 윈도우를 지원하는 배치 스크립트와 OSX, Linux를 지원하는 쉘스크립트를 포함하고 있습니다. 이러한 스크립트들은 Gradle이 설치되어있지 않은 시스템에서도 Gradle 빌드를 가능하게 해줍니다. build.gradle파일에 다음의 설정을 추가함으로써 래퍼를 설치할 수 있습니다.

task wrapper(type: Wrapper) {
    gradleVersion = '1.10'
}

그리고 다음의 명령을 통해 래퍼 스크립트를 다운받고 초기화 할 수 있습니다.

$ gradle wrapper

명령이 정상적으로 수행되고나면 몇몇 파일이 생성되었음을 알려줍니다. 두개의 스크립트 파일이 루트 디렉토리에 생성되고 래퍼 jar 파일과 설정 파일이 gradle/wrapper 디렉토리 안에 생성됩니다.

└── initial
    └── gradlew
    └── gradlew.bat
    └── gradle
        └── wrapper
            └── gradle-wrapper.jar
            └── gradle-wrapper.properties

당신의 프로젝트를 빌드하기 위한 Gradle Wrapper가 준비되었습니다. 기존에 설치했던 Gradle과 똑같은 방식으로 사용할 수 있습니다. 빌드를 수행하기 위해 기존에 수행했던 방법과 거의 흡사하게 다음의 명령을 수행하면 됩니다.

$ ./gradlew build

특정 버전의 Gradle Wrapper를 처음으로 실행하게 되면 해당 버전의 Gradle 바이너리를 다운받고 캐시하게 됩니다. Gradle Wrapper는 어떤 유저라도 프로젝트를 개발하기 위해 같은 버전의 Gradle 환경을 구축할 필요 없이 소스 코드의 개발에 전념할 수 있도록 설계되어있습니다.

다음은 지금까지 다루었던 내용이 모두 기술 된 build.gradle 파일입니다.

apply plugin: 'java'
apply plugin: 'eclipse'

repositories { mavenCentral() }
dependencies {
    compile "joda-time:joda-time:2.2"
}

task wrapper(type: Wrapper) {
    gradleVersion = '1.8'
}

참고 : https://spring.io/guides/gs/gradle/