Web

[Gradle] build.gradle를 톺아보자

soro.k 2023. 2. 4. 23:39

 

이번에 새로 강의를 들으면서 Gradle을 사용하는데 build.gradle에 의존성을 추가하다 보니 정확히 설정을 잘 모르고 사용하고 있다는 생각이 들어 공부를 시작하기로 했다. 

 

 

Plugin

Gradle의 플러그인은 프로젝트의 기능을 확장하는 역할을 한다. 처음에는 어떤 특별한 기능들이 더 제공된다는 이야기인가하고 헷갈렸는데 그게 아니라 예를 들어 해당 플러그인이 자바라면 자바가 제공하는 코드를 컴파일 한다던지, 혹은 소스 파일 설정과 같은 다양한 번들 기능이 추가된다는 이야기였다. 

 

plugins {} 구문의 특징

plugins {
    id 'java'
}

첫 번째로 이 구문은 항상 빌드 스크립트 최상위에 위치해야 하고 다른 구문 안에 중첩되게 사용하지 않고 위와 같이 단독으로 써야 한다. 두 번째로 내부에 허용되지 않는 코드는 작성할 수 없어서 만약 작성한다면 컴파일 오류가 난다. 세 번째로 안에 추가되는 플러그인은 멱등성이라는 특징을 가지고 있어서 동일한 플러그인이 여러 번 사용되어도 문제가 발생하지 않는다. 그러니까 'java'를 여러 번 추가해도 전혀 문제가 없어서 개발자가 실수를 해도 잘 작동되게 알아서 걸러준다는 의미이다.

 

 

Java 플러그인

java는 표준 Gradle 플러그인에 포함된 코어 플러그인이기 때문에 id에 짧게 'java'라고 적어주면 된다. 그러면 Java 플러그인은 프로젝트에 테스트 및 번들 기능 그리고 컴파일 작업 등을 할 수 있도록 추가한다. 위에서 이야기했듯이 JVM 위에서 프로젝트 작업을 하기 위해 기본 구성 요소들을 추가하는 것이라고 생각하면 된다. 

 

참고로 JVM 기반으로 사용되는 플러그인들은 다음과 같다.

 

Tasks

아래의 그림은 자바 플러그인을 추가했을 때 프로젝트에서 어떤 작업들을 할 수 있는지 관계로 표현한 것인데 jar 파일을 만드는 작업이나, API 문서를 만드는 javadoc 그리고 test 등 여러 가지 작업들이 추가된 것을 알 수 있다. 아래에 나와있는 작업 외에도 프로젝트 레이아웃 구조를 미리 가정해서 컴파일을 해주거나 누락된 게 있으면 처리도 하고 Gradle이 소스 기반 프로젝트를 구축하기 위해서 지원하는 source set에 대한 정보와 작업도 추가된다. 여기서 source set은 프로덕션 코드와 테스트 코드로 나뉘는 'main'과 'test'를 생각하면 된다. 

 

 

 

 

Dependency configurations

Java의 class path는 두 가지 종류가 있다. Compile class pathJDK가 소스 파일을 class파일로 컴파일할 때 필요한 의존성 목록이고, Runtime class path컴파일된 코드를 실제로 실행할 때 필요한 의존성 목록을 말한다. 우리는 어떤 의존성을 어떤 class path에 추가할지를 선언할 수가 있는데 이때 사용하는 것이 Gradle의 의존성 설정들이다.

 

아래는 자바 플러그인의 main source set의 의존성 설정에 대한 그림이다. 위에서 설명한 것처럼 자바를 컴파일 하는 작업(compileJava)을 할 때 compileClasspath에 있는 의존성 목록들을 사용하는 것을 확인할 수 있다. 그리고 compileOnly와 implementation, 그리고 runtimeOnly가 우리가 어떤 class path에 의존성을 추가할지 scope를 정할 수 있게 해주는 의존성 설정들이다. 

 

출처 : https://docs.gradle.org/current/userguide/java_plugin.html#java_source_set_tasks

 

  • implementation
    • 런타임과 컴파일 시점에 모두 사용될 의존성일 때
  • compileOnly
    • 컴파일 타임에만 사용될 의존성일 때
  • runtimeOnly
    • 런타임에만 사용될 의존성일 때

 

 

아래는 test source set에 대한 그림인데 기본적으로 위의 세 가지 개념이 적용된다고 이해하고 보면 된다.

출처 : https://docs.gradle.org/current/userguide/java_plugin.html#java_source_set_tasks

 

 

이렇게 class path 별로 의존성을 설정하는 이유는 무엇일까? 모든 의존성을 런타임, 컴파일 시점 구분없이 implementation을 통해 추가한다면 개발자는 컴파일과 런타임 구분없이 그저 의존성을 추가하기만 하면 되기 때문에 편하겠지만, 특정 시점에 필요하지 않은 의존성이 추가되는 것이기 때문에 여러 면에서 좋지 않다. 우선 컴파일 class path에는 컴파일 시점에 필요한 의존성들만 추가되기 때문에 모든 의존성들이 추가됐을 때보다 더 빠른 속도로 컴파일을 할 수 있다. 그리고 서로 다른 시점에 필요한 의존성의 클래스들을 사용하지 않을 수 있어서 혹시 모를 실수를 방지할 수 있다. 마지막으로 이렇게 잘 구분된 class path들은 복잡하지 않고 관리하기 용이하다. 

 

 

 

정리

  • build.gradle의 plugin은 프로젝트의 기능을 확장하기 위해 사용한다.
  • build.gradle의 dependency configurations로 class path scope를 지정할 수 있다.
  • scope를 지정하는 이유는 특정 시점에 필요한 의존성만 추가하여 관리를 용이하게 하고 컴파일 속도를 향상시키거나 실수를 방지하기 위함이다.

 

 

참고