본문 바로가기
Back-End

자동 배포로 한걸음 다가가기 - 빌드 관리 도구 Gradle

by newny 2024. 1. 5.
반응형

Intro

자동 배포에 대해서 공부하다 보니 빌드에 대한 지식이 부족함을 느꼈다.
항상 프로젝트를 생성함과 동시에 빌드 도구가 나도 모르는 사이 다운받아져서 당연한 듯 사용하다 보니, 언제 다운받아지고 어떻게 사용되는지에 대해 깊게 모르고 있었다. 그래서 오늘은 빌드 관리도구가 정확히 어떤 일들을 도맡고 있는지, 그중에서도  Gradle은 어떻게 동작하는지에 대해서 알아보려 한다.
 
 

빌드 도구란?

소프트웨어 개발에 있어서 소스 코드를 실행 가능한 애플리케이션으로 만들어주는 도구를 뜻한다.
프로젝트를 진행하게 되면 단순히 자신이 작성한 코드만드로 개발하는 것이 아니라 많은 라이브러리들을 활용해서 개발을 하게 된다. 이때 사용되는 라이브러리들의 수가 굉장히 많아진다면 관리하기가 수월하지 못할 수 있다.(빌드 도구를 사용하지 않으면 필요한 라이브러리를 개발자가 열심히 다운 받아서 관리해야 한다) 빌드 도구는 이러한 문제를 해결해 줄 수 있다. 해당 프로젝트에 사용된 라이브러리를 작동하는데 필요한 다른 라이브러리들까지도 관리하여 자동으로 다운 받아준다.
 
 

빌드 도구는 언제 다운 받아질까?

예를 들어 오늘 설명할 Gradle로 설명을 해보겠다. 빌드 도구로 Gradle을 선택하여 프로젝트를 생성했다고 가정했을 때, 프로젝트 디렉토리에 Gradle Wrapper(IntelliJ의 경우에는 ~/gradle/wrapper/ 경로에 다운 받아짐)와 Gradle Wrapper 파일들(gradlew, gradle-wrapper.properties 등)이 IDE를 통해 자동으로 프로젝트 디렉토리에 생성된다. 이후 첫 빌드 또는 Gradle 버전 변경 시에 Gradle Wrapper가 해당 프로젝트에 지정된(gradle-wrapper.properties에 Gradle 버전이 명시되어 있음) Gradle 버전을 다운로드한다. 이후 IDE에서 Gradle 빌드 도구가 build.gradle 파일을 실행하여 프로젝트를 빌드하거나 테스트를 실행시킨다. 이때 필요한 라이브러리 및 플러그인이 Gradle을 통해 자동으로 다운로드되어 사용된다.
우리의 IDE는 위의 과정을 사용자도 모르게 빠른 속도로 진행시키고 있던 것이다.
 
 

빌드 도구 Gradle

빌드 도구 Gradle을 설명하기 전에 '왜 Gradle을 사용하냐?'라고 물으신다면, 대답해 드리는 게 인지상정

Gradle을 사용하는 이유는 개인적으로는 Maven과 Gradle을 둘 다 사용해 본 결과 Gradle이 사용하기가 더 수월해서였다. Maven의 경우 태그문법이 기반되기 때문에 가독성이 떨어지고, 작성하기에도 번거로웠는데, Gradle의 경우는 Java 언어 쓰듯 비슷한 형식으로 쓸 수 있다는 장점이 좋았다.(물론 Groovy언어와 Java언어는 다르다)
그리고 두 번째 이유는 요즘 많이 쓴다는 추세 때문이었다.ㅎ
 

그렇다면 요즘 추세가 Maven보다 Gradle을 선호한다는데 이유가 무엇일까?

먼저 Gradle은 유연성과 확장성이 좋다고 한다. Gradle은 Java, Kotlin, Groovy, C++ 등 다양한 언어로 작성된 프로젝트에 대한 빌드를 지원한다. 플러그인 기반의 아키텍처를 제공하기에 개발자가 필요에 따라 빌스 시스템을 확장할 수도 있다는 장점이 있다.(개발자가 커스텀해서 쓰기 좋다~ 정도로 생각하면 될듯하다)
또한 Gradle은 변경된 부분만 빌드하는 증분 빌드(incremental build)를 지원하여 전체 빌드 시간을 단축시킬 수 있다고 한다.
또 또한 멀티 프로젝트에서 하나의 빌드로 관리할 수 있도록 지원해준다고 하니 안쓸 이유가 없겠다.
물론 내가 Gradle을 선택한 이유는 좀 더 간단한 이유였지만, 위와 같은 이유들을 보니 Gradle을 선호할 수밖에 없겠구나 생각이 든다.
 
 

자 이제 Gradle에 대해서 파고들어 보려 한다.

아무래도 목차는 아래와 같을 것 같다. 생각보다 길어질 것 같지만 나눠서 쓰기는 싫으니까 한방에 정리하려 한다.

1. Gradle Wrapper는 뭐 하는 애지?
2. gradle-wrapper.properties는 Gradle Wrapper의 설정 정보를 담고 있는 파일인 게 분명하지만 그래도 다시 알아보자
3. settings.gradle 파일에는 rootProject.name 밖에 없던데 왜 존재하는 것일까?
4. gradlew, gradlew.bat 너네는 뭐 하는 애들이니
5. 모두가 아는 build.gradle
6. Gradle 빌드 프로세스 작업 단계

 
 

Gradle Wrapper는 뭐하는 애지?

먼저 Gradle Wrapper라는 이름 대해서 얘기해 보자면 단어 그대로 Gradle을 감싸서(wrap) 프로젝트에 내장시키는 역할을 하기에 그 이름이 Gradle Wrapper가 되었다고 한다. 굉장히 직관적인 이름이다.
여튼, 이름 그대로 Gradle Wrapper는 Gradle빌드 도구를 프로젝트에 포함시키는 도구이다. 그리고 Gradle의 버전이 바뀌었을 경우 그 버전에 맞는 Gradle 도구를 다운로드해주기도 한다.
Gradle Wrapper의 핵심 JAR 파일은 IntelliJ의 경우 '~/gradle/wrapper/' 경로에 'gradle-wrapper.jar'의 형태로 위치한다. 해당 파일은 Gradle을 실행하는 데 필요한 코드와 리소스를 포함하며, Gradle을 로컬 시스템에 설치하지 않고도 프로젝트에서 실행할 수 있게 하는데 사용된다.
결론적으로 Gradle Wrapper는 Gradle 빌드 도구를 프로젝트 내에 위치시키는 역할을 하며, 로컬에 Gradle을 설치할 필요 없이 gradlew 또는 gradlew.bat 스크립트를 통해 Gradle 명령어를 실행할 수 있도록 하는 역할을 한다.
 
 

gradle-wrapper.properties는 Gradle Wrapper의 설정 정보를 담고 있는 파일인 게 분명하지만 그래도 다시 알아보자

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

위의 코드는 내 프로젝트의 gradle-wrapper.properties 내용을 그대로 가져온 것인데, 내용을 보면 어느 경로에 Gradle을 다운받을지, Gradle을 어느 경로에서 다운받아올지와 다운받을 버전등이 적혀있다.(나머지는 모르겠다ㅎ) 
여튼, gradle-wrapper.propertiis는 위의 소제목 그대로 Gradle Wrapper의 설정 정보들을 가지고 있는 파일이다. 위 파일의 내용을 기반으로 Gradle Wrapper가 Gradle 빌드 도구를 다운받아준다. 크게 어려운 부분은 없어서 이만하고 넘어가도 될듯하다.
 
 

settings.gradle 파일에는 rootProject.name 밖에 없던데 왜 존재하는 것일까?

항상 settings.gradle 파일을 들어갈 때마다 '이거 하나 쓰여있을 거면 왜 있지?'가 뇌리에 박힌다. settings.gradle 파일의 존재 이유를 알아보자.
settings.gradle 파일은 기본적으로 루트 디렉토리에 위치하며, Gradle을 기반으로 한 프로젝트의 구성을 정의하는 파일이라고 한다. 이것이 무슨 말인가 하면, 위쪽의 글들 중 Gradle을 권장하는 이유에 대한 글에서 '멀티 프로젝트에서 하나의 빌드로 관리할 수 있도록 지원'이라는 부분이 있는데 settings.gradle 이 부분을 담당하고 있다는 얘기이다. 그렇기 때문에 나는 여태 settings.gradle의 의미를 이해 못 했다. 왜냐하면 멀티 프로젝트를 해본 적이 없기 때문이다.ㅎ
여튼, 존재 이유는 알았으니 settings.gradle의 역할을 자세히 알아보자.
 

// 단일 프로젝트의 경우
rootProject.name = 'my-single-project'

// 멀티 프로젝트의 경우
include 'module1', 'module2'

rootProject {
    // 루트 프로젝트 초기화 블록
    // ...
}

allprojects {
    // 모든 프로젝트에 공통으로 적용할 초기화 블록
    // ...
}

1. 프로젝트 구성 및 이름 정의
위의 코드에서 보이는 바와 같이 settings.gradle은 프로젝트 구조를 정의하고, 각 모듈이나 서브 프로젝트의 이름을 설정한다. 이 파일에서 프로젝트 및 서브 프로젝트의 이름을 지정하면 Gradle은 해당 이름으로 프로젝트를 인식하고 빌드한다.
 
2. 포함할 모듈 지정
위의 코드에서 보이는 'include' 구문을 이용하여 멀티 프로젝트에서 포함할 각 모듈을 지정한다. 이를 통해 Gradle은 각 모듈에 대한 프로젝트를 생성하고 빌드한다.
 
3. 커스텀 설정 및 초기화
프로젝트의 루트에서 초기화 블록을 사용하여 추가적인 커스텀 설정이나 초기화 로직을 수행할 수 있다. Gradle 빌드 단계 중 초기화 단계 (Gradle 빌드 스크립트 실행 전)가 있는데 그때에 실행된다. Gradle 빌드 단계에 대해서는 아래에서 더 자세히 설명하겠다.
 
결론적으로 settings.gradle 파일은 프로젝트의 구성을 정의하는 파일이며, 여러 모듈로 구성된 멀티 프로젝트 빌드에서 사용된다. 또한 초기화 블록을 사용하여 원하는 프로젝트 또는 모든 프로젝트가 빌드되기 전 수행될 초기화를 진행시킬 수 있다.
 
 

gradlew, gradlew.bat 너네는 뭐 하는 애들이니

여태까지의 부제목들은 내가 gradle 공부를 하며 느낀 대로 적은 것이다. gradlew 같은 경우는 dockerfile을 공부할 때 dockerfile 내부에 적었던 명령어 정도로만 알고 있었고 '이 친구들로 인하여 프로젝트 파일을 빌드할 수 있다(?)' 정도로만 알고 있었다. 그들의 정확한 내막을 파헤쳐보자.
 

gradlew와 gradlew.bat은 무려.. Gradle Wrapper의 스크립트였다!!(나만 몰랐던 듯)

Gradle Wrapper가 Gradle 빌드 도구를 프로젝트에 내장시키고, 특정 Gradle 버전을 프로젝트와 함께 사용할 수 있도록 하며, 로컬 시스템에 Gradle을 별도로 설치하지 않고도 Gradle 프로젝트를 빌드할 수 있게 하는 역할을 한다고 위쪽 글에 적어놓았는데, 실질적으로 그 역할을 할 수 있도록 적어놓은 스크립트였던 것이었다. 헐ㅎ
여튼, 그들은 가장 핵심적인 역할을 하는 친구들이었다.
 
gradlew는 Unix(Linux, MacOS) 계열 운영체제에서 사용되는 Gradle Wrapper 스크립트 파일이고, gradlew.bat은 윈도우 운영체제에서 사용되는 Gradle Wrapper 스크립트 파일이다. (어쩐지 gradlew로 빌드하려고 하니 안되더라... 빨리 취업해서 윈도우에서 벗어나고 싶다ㅎ)
 
결론적으로 gradlew, gradlew.bat은 가장 핵심적인 역할을 수행하는 Gradle Wrapper의 스크립트 파일이었다. 이제 내가 쓰고 있는 명령어가 뭘 뜻하는 것인지 인지하고 빌드할 수 있을 것 같다.
 
 

모두가 아는 build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.5'
    id 'io.spring.dependency-management' version '1.1.3'
}

group = 'com'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.mysql:mysql-connector-j'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

Gradle 기반의 프로젝트를 만들어 본 개발자들이라면 build.gradle에 어떠한 내용들이 포함되어 있는지 알 것이다. 프로젝트에서 사용하는 외부 라이브러리를 자동으로 다운로드하고 관리하며, 실행 파일을 생성하고(JAR 또는 다른 실행파일), 테스트를 수행하고, 생성된 실행 파일을 자동으로 지정된 위치에 복사하거나 더 나아가서 저장소에 배포하는 역할을 한다. 
 
 

Gradle 빌드 프로세스 작업 단계

Gradle에는 미리 정의된 빌드 태스크(clean, build, assemble, check 등)가 있다. 그렇기에 개발자는 편리하게 빌드 프로세스를 실행할 수 있다. 사용자가 ./gradlew build와 같은 명령을 실행하면 기본적으로 build 프로세스가 실행되며, 이에 따라 compile, assemble, test, jar 등 다양한 빌드 태스크가 순서대로 실행된다. 그 단계는 아래의 순서대로 진행된다.

  1. 초기화 단계 (Initialization)
    • settings.gradle 파일을 읽어 프로젝트 이름이 무엇인지, 프로젝트에 어떤 모듈들이 있는지를 확인 (프로젝트 계층 구조 설정)
    • 멀티 모듈 프로젝트일 경우 build.gradle 파일이 각 모듈에 존재하는지 확인
    • 이때에 settings.gradle 파일에 초기화 블럭이 있다면 실행됨
  2. 구성 단계 (Configuration)
    • build.gradle 파일을 해석하여 프로젝트 객체를 생성
    • Gradle은 프로젝트와 모든 하위 프로젝트의 설정을 읽어 들이고, 각 태스크의 의존성 관계를 파악함 → 프로젝트 구조, 의존성, 플러그인 적용 등에 대한 설정이 이루어지는 단계
  3. 실행 단계 (Execution):
    • Compile, Test, 패키징(Jar, War, Aab, Apk)을 하는 단계
  4. 정리 단계 (Finalization):
    • 빌드 프로세스가 완료된 후에는 정리 단계에서 리소스를 정리하고 마무리 작업을 수행

 
 

참고) IntelliJ에서 빌드된 파일의 경로

  • IDE 내부에서 프로젝트 실행 시 사용하는 파일들은 프로젝트의 out 디렉토리 내부에 생성된다.
  • 빌드 후 JAR 파일을 생성했을 경우 out 디렉토리 안의 artifacts 디렉토리에 JAR파일이 생성된다.

 
 

결론

결론적으로 Gradle은 프로젝트의 구성에 관련된 모든 부분에 대해서 책임을 지고 있다는 것이다. 외부 라이브러리에 대한 의존성 관리, 프로젝트 구성의 정의, 실행 파일 생성, 테스트 코드 실행 등 정말 많은 일들을 도맡아 하고 있다는 것을 새삼 느끼게 되었다. 
Gradle을 사용하면서 build.gradle 파일 내부에 dependencies에 의존성 주입할 외부 라이브러리나 적을 줄만 알았지 이렇게까지 상세한 과정은 몰랐었다. 그러다 보니 자동 배포 공부를 할 때 빌드 자체에 이해가 안 되는 부분들이 많았는데, 빌드 과정을 공부하니 그 부분들에 대한 해소가 되었다.
이제는 빌드과정에서 오류가 생기게 되면 오류 내용을 보고 어느 부분으로 인한 오류인지 고개를 끄덕일 수 있을 정도는 될 것 같다.
 
 

참고
반응형

'Back-End' 카테고리의 다른 글

Spring Boot 프로젝트 local 환경에서 https 적용하기  (0) 2024.05.31
Mapstruct 적용기  (0) 2024.05.16
MyBatis  (0) 2023.05.16

댓글