gradle을 사용하여 multi module 만들기

minseok·2024년 11월 14일
0
post-thumbnail

+ 목표

  1. gradle build tool을 사용하여 multi module 만들기 (spring 아님)



+ multi module을 만들기

gradle 버전은 8.11 버전을 사용했습니다.

1. 깡통 폴더 만들기

인텔리 제이를 통해서 만들지 않고 직접 폴더를 만들어서 들어갑니다.





2. gradle 프로젝트 초기화

gradle project 초기화 명령어 입니다. (명령어 위치는 root 디렉토리에서 실행시킵니다.)
gradle init --type java-application --dsl kotlin

잘 동작은 하지만, 코틀린 프로젝트를 만들고 싶으니 type option의 값을 "kotlin project"으로 변경합니다.
gradle init --type kotlin-application --dsl kotlin


kotlin-application 옵션 설정 시 app/build.gradle.kts에 아래 같이 설정됩니다.
(다른 설정들도 포함되지만 kotlin 코드를 실행하기 위한 최소 조건은 아니기 때문에 생략합니다.)


plugins {
    // kotlin 파일 컴파일 지원
    // 해당 plugin을 넣어야 build/classes에 컴파일 결과물을 넣어줍니다.
    alias(libs.plugins.kotlin.jvm)
	...
}

...

application {
    // fun main() 같이 class 외부에 함수를 선언한 경우 컴파일 결과물(.class)에 접미사로
    // Kt가 들어가는 경우를 위해 설정
    // 해당 설정이 없는 경우 task에서 메인 함수를 찾을 수 없을 수 있습니다.
    mainClass = "org.example.AppKt"
}



명령어를 입력하면 아래 같이 출력됩니다.
init Task 완료 후 프로젝트 구성하는 방법을 알려주는 링크도 걸어주니 참고해도 좋습니다.

https://docs.gradle.org/8.11/samples/sample_building_kotlin_applications.html

Enter target Java version (min: 7, default: 21):

Project name (default: multi-modules): 

Select application structure:
  1: Single application project
  2: Application and library project
Enter selection (default: Single application project) [1..2] 1

Select test framework:
  1: kotlin.test
  2: JUnit Jupiter
Enter selection (default: kotlin.test) [1..2] 1

Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] 


> Task :init
Learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.11/samples/sample_building_kotlin_applications.html

이제 아래 같이 템플릿이 완성됩니다.





3. module 추가하기

multi module을 만들 것이니 app 패키지 내부의 구조를 아래처럼 수정해줍니다. 저는 app안에 service, shared module을 만들었습니다.

이제 root 디렉토리에 settings.gradle.kts를 수정해줍니다.
아래는 gradle init으로 프로젝트 초기화 시 기본 세팅입니다.

/*
 * This file was generated by the Gradle 'init' task.
 *
 * The settings file is used to specify which projects to include in your build.
 * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.11/userguide/multi_project_builds.html in the Gradle documentation.
 */

plugins {
    // Apply the foojay-resolver plugin to allow automatic download of JDKs
    id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}

rootProject.name = "multi-modules"
include("app")

include 함수에 우리가 만든 module을 설정해줍니다. 처음에는 app module이 있기때문에 이를 등록하기 위해 `include("app")`이 들어가있습니다.

우리는 app에 service와 shared 모듈을 등록할 것이기 때문에 아래같이 수정합니다.
include(":app:service", ":app:shared")


reload gradle change를 해주면 intelliJ의 gradle 탭에 반영이 됩니다.

task에 documentation, distribution.. 같이 좀 복잡한게 많네요. 이해에 방해가될 수 있으니 밀어버립니다. task는 plugin 함수의 인자에 영향을 받습니다. 현재 application, alias(libs.plugins.kotlin.jvm) 2가지 plugin이 존재합니다.

application plugin - module에 run task를 추가


좌측이 service 모듈 build.gradle.ktx
우측이 shared 모듈 build.gradle.ktx

service 모듈의 build.gradle.ktx 내용도 모두 삭제해줍니다.





4. service module 코드 실행시키기

서브 모듈끼리 참조하여 기능을 실행하기 전에 service 모듈만 정상 동작하는지 테스트해봅니다.

service 모듈의 build.gradle.kts를 아래처럼 수정하고 새로고침 해줍니다.

plugins {
    // 코틀린 컴파일 지원
    alias(libs.plugins.kotlin.jvm)
    // run task 추가
    application
}

// plugin, library 의존성 저장소 지정
repositories {
    mavenCentral()
}

// 코틀린 main class 지정
application {
    mainClass = "com.AppKt"
}

우측에 gradle 탭에서 run을 클릭하면 결과물(build/..)이 생기고 classes 디렉토리의 AppKt.class를 실행시켜줍니다. 터미널에 run task의 결과로 "hello kotlin!"가 출력됩니다.





5. shared 모듈 참조하기

이제 shared 모듈의 함수를 servcie 모듈에서 사용하겠습니다.
service 모듈의 build.gradle.kts에 shared 모듈을 사용하겠다는 설정을 추가해야합니다.

file: builde.gradle.kts
---

dependencies {
    implementation(project(":app:shared"))
}

이제 shared 모듈에 간단한 기능을 만들어봅니다.

file: Machine.kt
---

package org

class Machine {
    val value = 50
    fun getValue() = value
}

다음으로 shared 모듈의 build.gradle.kts를 설정합니다. shared 모듈은 단독으로 실행시키지 않겠다는 의미로 application plugin 설정은 제외했습니다.

file: build.gradle.kts
---

plugins {
    // 코틀린 컴파일 지원
    alias(libs.plugins.kotlin.jvm)
}

// plugin, library 의존성 저장소 지정
repositories {
    mavenCentral()
}

이제 service 모듈의 run task를 클릭하면 shared 모듈의 Machine이 반환하는 값을 참조해서 "hello 50"이 출력됩니다.

이렇게 하면 multi module이 완성되었습니다. 빌드 자동화 도구를 사용은 많이 했었지만 spring initializer의 도움을 받거나 복붙을 활용해서 세팅을 해서 학습 차원으로 만들었습니다.





5. 조금 더 수정해보기

목표는 달성했지만 중복 설정을 최소화하는 작업을 해보겠습니다.

https://docs.gradle.org/current/userguide/plugins.html#sec:subprojects_plugins_dsl

subprojects를 사용하면 하위 모듈들의 중복되는 설정을 1개의 파일에서 관리할 수 있습니다.

root project에 build.gradle.kts를 추가해줍니다.

file: build.gradle.kts
---

plugins {
    alias(libs.plugins.kotlin.jvm)
}

// plugin, library 의존성 저장소 지정
repositories {
    mavenCentral()
}

subprojects {
    plugins.apply("org.jetbrains.kotlin.jvm")
    // plugin, library 의존성 저장소 지정
    repositories {
        mavenCentral()
    }
}

subprojects에 하위 모듈들에 공통적으로 추가하고 싶은 설정을 빼주면은 적용됩니다. 이제부터 하위 모듈마다 중복되는 공통 설정이 제거됩니다.

subprojects와 비슷한 allprojects가 존재하며 차이는 아래와 같습니다.
subprojects - root module 제외하고 적용
allprojects - root module까지 함께 적용



추가적으로 dependency, plugin도 한 파일에서 관리해보도록 합니다.
gradle/libs.versions.toml파일로 이동합니다.

아래처럼 프로젝트 전역적으로 사용되는 라이브러리, 플러그인을 해당 파일에서 정의한 후 gradle 설정 파일에서 libs 객체를 통해 참조해서 사용할 수 있습니다.

file: gradle/libs.versions.toml
---

[versions]
guava = "33.2.1-jre"
junit-jupiter-engine = "5.10.3"
gson = "2.11.0"

[libraries]
guava = { module = "com.google.guava:guava", version.ref = "guava" }
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit-jupiter-engine" }
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }

[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version = "2.0.20" }

service 모듈의 build.gradle.kts를 보면 아래처럼 libs를 통해서 관리할 수 있습니다.

file: build.gradle.kts
---

dependencies {
    implementation(project(":app:shared"))
    // libs.versions.toml 에서 정의한 값을 참조합니다.
    implementation(libs.gson)
}

libs를 통해 관리하면 서비스를 구성하는 모듈에 의존성을 추가할 때 실수로 다른 버전을 추가하는 문제를 대비할 수 있습니다. (예를 들어 A 모듈에는 Gson 1.52를 참조하는데 B 모듈에는 Gson 2.2를 참조)

모듈들의 동일 의존성은 모두 같은 버전을 사용해야 관리가 편할 것이라고 생각합니다.


참조
https://docs.gradle.org/current/userguide/part1_gradle_init.html

profile
즐겁게 개발하기

0개의 댓글