티스토리 뷰
jvm 기반 언어 빌드 자동화 tool
다른 선택지로는 maven, ant 정도가 있다. (이거 두개는 xml 기반이라 점점 안쓰는 추세)
- 편한 의존성 버전 관리
- 간단한 명령어 한개만 치면 효율적으로(캐싱), 언제나 같은 결과물을 보장하며 deployable unit을 만들어줌 (jar 파일)
- gradle build
- 테스트, lint 체크 등 부가적 기능도 제공
- gradle test
- gradle check
사용하는 이유
jdk안에 javac 라는 컴파일러가 들어있기는 하지만
빌드 자동화 툴 없이 쓴다면...
작성한 .java 파일 => .class 파일로 컴파일 => 여러개의 .class 파일 및 dependency 파일 모아서 .jar 파일 생성
이렇게 수동으로 해야함 너무 복잡하고 중복되는 커맨드가 많을 것이다..
.class 파일 => .java 파일 한개가 컴파일된 것
.jar 파일 => 여러개의 .class 파일 및 dependency들을 하나로 묶어 패키징 한 것.
(rails는 배포할 도커 이미지에 (1) 어플리케이션 코드 복사 + 젬락에 명시된 (2) 젬파일도 전부 다운로드 해야해서 무거운데,
스프링부트는 .jar 파일 안에 컴파일된 어플리케이션 코드 뿐만 아니라 dependecy도 모두 포함되어 있어서 더 경량이고 dockerfile 작성도 간단할 듯)
이 파일/디렉토리들은 뭘까?
- build : 빌드된 결과물 (class, jar 파일 및 테스트 결과)
- gradle : gradle wrapper 버전 설정 등 config 파일 (gradle-wrapper.properties)
- src : gradle은 자바 소스코드가 src/main/java 디렉토리 아래에 있기를 기대함.
- build.gradle : 빌드 스크립트. (maven의 pom.xml)
- build.gradle : 스크립트 언어 groovy
- build.gradle.kts : 스크립트 언어 kotlin
- gradlew : for mac, linux. gradle wrapper 스크립트.
- gradlew.bat : for window
- settings.gradle : high-level 프로젝트 config 설정 (rootProject.name)
gradlew (gradle wrapper)
- gradlew 스크립트 사용하면 gradle 미리 설치되어 있지 않아도 스크립트가 설치해서 실행해줌.
(bundle exec, npx 랑 좀 비슷한가..? system-wide gem 말고 프로젝트 Gemfile.lock에 명시된 버전의 젬으로 실행)
- 팀 내 프로젝트를 진행할 때 같은 gradle 버전으로 맞추고, git에서 버전관리도 할 수 있어서. 개발 구성원간 일관된 로컬 개발환경 마련하는데 도움을 줌.
전역으로 설치된 gradle 버전 확인 (brew나 sdkman으로 설치했을)
gradle --version
## sdkman을 사용한다면
sdk current gradle
(프로젝트별) gradlew의 gradle 버전
# 버전 확인
./gradlew --version
# 버전 바꾸기
# gradle/wrapper/gradle-wrapper.properties 파일 내용이 변경됨
# distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
./gradlew wrapper --gradle-version 8.4
gradle basic concepts
project
- 빌드 수행 단위.
- multi project 일 경우 빌드를 실행하면 sub project 별로 build 디렉토리가 생성됨.
task
- 빌드 프로세스에서 수행되는 단위 작업. unit of work (테스트, 컴파일, jar 파일 생성 등...)
- ./gradlew (task name) 으로 cli 에서 실행시킬 수 있음.
- 여러 task가 dependency graph 형태로 연결되어 있음. (gradle build는 내부적으로 assemble과 check task를 실행하는 것)
# 신규 task 등록하기 => register
# 이미 있는 task 추가 수정하기 => named
tasks.register('hello') {
doLast {
println 'original do Last'
}
}
tasks.named('hello') {
doLast {
println 'add do last 1'
}
}
tasks.named('hello') {
doLast {
println 'add do last 2'
}
}
tasks.named('hello') {
doFirst {
println 'add do first 1'
}
}
# > Task :hello
# add do first 1
# original do Last
# add do last 1
# add do last 2
# BUILD SUCCESSFUL in 451ms
# 1 actionable task: 1 executed
plugin
- task 묶음
- 사용자가 직접 task를 정의할 필요 없게 플러그인으로 제공됨. 높은 재사용성
- 예를 들어 java 플러그인은 java 개발을 위한 task 모음
- compileJava (.java -> .class 파일로 컴파일)
- processResources (resources 디렉토리 아래에 있는 파일들 build 디렉토리로 복사)
- jar (jar 파일로 패키징. <project name>-<version>.jar )
- test
( compileJava + processResources => classes 태스크 )
gradle 주요 command
empty gradle project 생성하기
gradle init
실행할 수 있는 task 목록
./gradlew tasks
빌드
- build 디렉토리 아래에 빌드 결과물 생김
- classes 디렉토리 : 아래에 src 디렉토리 구조 그대로 컴파일된 .class 파일 생성
- libs 디렉토리 : jar 파일
# check + assesmble
./gradlew build
build 디렉토리 삭제
./gradlew clean
springboot 실행
./gradlew bootRun
build script syntax
- 어플리케이션 코드 처럼 그냥 프로그램임. 커스텀 함수를 정의해서 사용할 수도 있음.
- build script 작성하는데 선택할 수 있는 언어
- groovy
- kotlin
plugins
plugins {
id 'java' # core gradle plugins
id 'com.example.hello' version '1.0.0' apply false
id 'com.example.goodbye' version '1.0.0' apply false
}
subprojects {
if (name.startsWith('hello')) {
apply plugin: 'com.example.hello'
}
}
# plugins bracket 바깥에서 apply 하려면
apply plugin: 'org.springframework.boot'
3rd party 플러그인일 경우 version 명시 해줘야함.
multi project 일 경우 root에 apply false로 설정한 다음에 필요한 subproject 에서만 apply 해서 사용하도록 할 수 있음.
build metadata
group = 'com.example'
version = '0.0.1-SNAPSHOT'
repositories
- dependency 다운로드 하는 저장소. 주로 mavenCentral. (Ivy, Google 이런 것도 있는 듯)
dependencies
- gradle이 다운로드해서 사용하는 jar 파일
- Group, name, version으로 구분.
- 의존성 구성 키워드
- implementations : 직접 참조
- api : 모든 하위 프로젝트와 의존성 공유. 전파됨
- compileOnly : 컴파일 시에만 필요한 의존성이다.
- runtimeOnly : 런타임에만 필요한 의존성이다.
- testImplementation / testCompileOnly : 테스트 코드에서만 사용되는 의존성이다.
- moduleX 에서 LibraryC 에 있는 메소드 직접 참조 불가능. (implementation 키워드로 의존성 설정)
- moduleX에서 LibraryD 에 있는 메소드 참조 가능. (api 키워드로 의존성 설정)
- LibraryC 코드가 수정되면 LibraryA (LibraryC를 직접적으로 참조하고 있는 모듈만), LibraryC만 다시 컴파일되면 됨.
- LibraryD 코드가 수정된다면 LibraryB, ModuleX 코드도 전부 다시 컴파일 되는 것이 맞음.
task 수정/설정
# task, plugin 수정/설정
#
# <task/plugin 이름> {
# // 설정
# }
# ./gradlew test는 기본적으로 junit4를 사용함...
# junit5를 사용할 수 있도록 test task 수정하는 코드
test {
useJUnitPlatform()
}
변수 / 프로퍼티
(kotlin 기준으로. groovy는 val 키워드 없이 쓰면 되는 듯)
변수 선언 및 사용
// 변수 선언
val projectName = "my-project"
val projectVersion = "1.0.0"
// 변수 사용
println("Project Name: $projectName")
println("Project Version: $projectVersion")
프로퍼티 설정
### 1. gradle.properties에 값
kotlinVersion=1.7.0
springBootVersion=2.6.0
springDependencyManagementVersion=1.1.2
# settings.gradle 에서 변수에 값 할당
val kotlinVersion: String by settings
val springBootVersion: String by settings
val springDependencyManagementVersion: String by settings
# build.gradle 에서 변수에 값 할당
val projectGroup: String by project
val applicationVersion: String by project
### 2. ext 블럭 정의한 프로퍼티
ext {
kotlinVersion = "1.7.0"
springBootVersion = "2.6.0"
springDependencyManagementVersion = "1.1.2"
}
task printProperties {
doLast {
println "myProperty: $myProperty"
println "apiUrl: $apiUrl"
println "versionCode: $versionCode"
}
}
multi project build
root 프로젝트 1개와 여러개의 sub project들로 구성.
├── .gradle
│ └── ⋮
├── gradle
│ └── wrapper
├── gradlew
├── gradlew.bat
├── settings.gradle (1)
├── subproject-one
│ └── build.gradle (2)
└── subproject-two
└── build.gradle (2)
# (1) : root 프로젝트 settings.gradle 파일은 모든 sub 프로젝트에 대한 정보를 담고 있어야 함.
# (2) : 모든 sub 프로젝트는 각자의 build.gradle 파일을 포함해야 함.
allProjects 블록 => 모든 프로젝트에 대한 설정을 일괄적으로 적용.
subProjects 블록 => 현재 프로젝트의 하위 프로젝트에 대한 설정을 정의.
그냥 외부 블록 => 현재 프로젝트에만 적용.
gradle lifecycle
1. initialization
- settings.gradle 파일을 읽어 멀티 프로젝트 구성을 초기화
# settings.gradle
rootProject.name = 'project-name'
include 'sub-proj1', 'sub-proj2', 'sub-proj3'
2. configuration
- 빌드 스크립트 (build.gradle) 실행해서 태스크 그래프 구성.
- root project 먼저 -> 하위 프로젝트 순으로 build.gradle 읽고 config 하는 것 실행됨. (breadth-frist ordering)
# 자식 cofig 먼저 실행하고 싶으면
# 부모 gradle.build 에다가
evaluationDependsOnchildren()
3. execution : 태스크 (의존성 순서대로) 실행
* root 프로젝트 말고 특정 하위 프로젝트에서 task 실행하려면
./gradlew :common:clean
References
multi project build 관련 공식문서 : https://docs.gradle.org/current/userguide/intro_multi_project_builds.html
implementation vs api : https://bluayer.com/13
'조각글' 카테고리의 다른 글
SDKMAN (0) | 2023.10.08 |
---|---|
golang 모듈 (0) | 2023.04.05 |
devops 따라하기 시리즈 (0) | 2022.03.22 |
영역함수 (0) | 2021.11.05 |
git 빠르게 시작하기 2 (내부 구조) (0) | 2021.02.26 |