[번역] Gradle 공식문서 - Understanding the Build Lifecycle

공혁준·2022년 3월 22일
0
post-thumbnail

Ref. Gradle v.7.4.1
📌 이 글에서는 공식문서의 Understanding the Build Lifecycle 부분만 다룹니다.

Build Lifecycle

Gradle의 핵심은 의존성 기반 프로그래밍을 위한 언어라는 것입니다. Gradle 용어로 이것은 작업과 작업 간의 종속성을 정의할 수 있음을 의미합니다. Gradle은 이러한 작업이 종속성 순서대로 실행되고 각 작업이 한 번만 실행되도록 보장합니다. 이러한 작업은 방향성 비순환 그래프를 형성합니다. 작업을 실행할 때 이러한 종속성 그래프를 작성하는 빌드 도구가 있습니다. Gradle은 작업이 실행되기 전에 완전한 종속성 그래프를 빌드합니다. 이것은 Gradle의 핵심이며 다른 방법으로는 불가능했던 많은 일을 가능하게 합니다.

빌드 스크립트는 이 종속성 그래프를 구성합니다. 따라서 엄밀히 말하면 build configuration scripts(빌드 구성 스크립트)입니다.

Build phases

Gradle 빌드에는 세 가지 별개의 단계가 있습니다.

  • Initialization(초기화)

    Gradle은 단일 및 다중 프로젝트 빌드를 지원합니다. 초기화 단계에서 Gradle은 빌드에 참여할 프로젝트를 결정하고 이러한 각 프로젝트에 대한 Project 인스턴스를 생성합니다.

  • Configuration(구성)

    이 단계에서 프로젝트 개체가 구성됩니다. 빌드의 일부인 모든 프로젝트의 빌드 스크립트가 실행됩니다.

  • Execution(실행)

    Gradle은 실행될 구성 단계에서 생성 및 구성된 작업의 하위 집합을 결정합니다. 하위 집합은 gradle 명령과 현재 디렉터리에 전달된 작업 이름 인수에 의해 결정됩니다. 그런 다음 Gradle은 선택한 각 작업을 실행합니다.

Settings file

빌드 스크립트 파일 외에 Gradle은 설정 파일을 정의합니다. 설정 파일은 명명 규칙을 통해 Gradle에 의해 결정됩니다. 이 파일의 기본 이름은 settings.gradle입니다. 이 장의 뒷부분에서 Gradle이 설정 파일을 찾는 방법을 설명합니다.

설정 파일은 초기화 단계에서 실행됩니다. 다중 프로젝트 빌드에는 다중 프로젝트 계층 구조의 루트 프로젝트에 settings.gradle 파일이 있어야 합니다. 설정 파일이 다중 프로젝트 빌드에 참여하는 프로젝트를 정의하기 때문에 필요합니다(다중 프로젝트 빌드 작성 참조). 단일 프로젝트 빌드의 경우 설정 파일은 선택 사항입니다. 포함된 프로젝트를 정의하는 것 외에도 빌드 스크립트 클래스 경로에 라이브러리를 추가하는 데 필요할 수 있습니다. 먼저 단일 프로젝트 빌드로 몇 가지 내성을 수행해 보겠습니다.

  • settings.gradle
rootProject.name = 'basic'
println 'This is executed during the initialization phase.'
  • build.gradle
println 'This is executed during the configuration phase.'

tasks.register('configured') {
    println 'This is also executed during the configuration phase, because :configured is used in the build.'
}

tasks.register('test') {
    doLast {
        println 'This is executed during the execution phase.'
    }
}

tasks.register('testBoth') {
	doFirst {
	  println 'This is executed first during the execution phase.'
	}
	doLast {
	  println 'This is executed last during the execution phase.'
	}
	println 'This is executed during the configuration phase as well, because :testBoth is used in the build.'
}
  • gradle test testBoth의 출력
> gradle test testBoth
This is executed during the initialization phase.

> Configure project :
This is executed during the configuration phase.
This is executed during the configuration phase as well, because :testBoth is used in the build.

> Task :test
This is executed during the execution phase.

> Task :testBoth
This is executed first during the execution phase.
This is executed last during the execution phase.

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed

빌드 스크립트의 경우 속성 액세스 및 메서드 호출이 프로젝트 개체에 위임됩니다. 마찬가지로 설정 파일 내의 속성 액세스 및 메서드 호출은 설정 개체에 위임됩니다.

Initialization

Gradle은 단일 또는 다중 프로젝트 빌드를 수행할지 여부를 어떻게 알까요? settings.gradle 파일이 있는 디렉토리에서 다중 프로젝트 빌드를 트리거하면 Gradle이 이를 사용하여 빌드를 구성합니다. Gradle을 사용하면 빌드에 참여하는 모든 하위 프로젝트 내에서 빌드를 실행할 수도 있습니다. settings.gradle 파일이 없는 프로젝트 내에서 Gradle을 실행하면 Gradle은 다음과 같은 방식으로 settings.gradle 파일을 찾습니다.

  • 상위 디렉토리에서 settings.gradle을 찾습니다.
  • 찾을 수 없으면 빌드가 단일 프로젝트 빌드로 실행됩니다.
  • settings.gradle 파일이 발견되면 Gradle은 현재 프로젝트가 발견된 settings.gradle 파일에 정의된 다중 프로젝트 계층 구조의 일부인지 확인합니다. 그렇지 않은 경우 빌드는 단일 프로젝트 빌드로 실행됩니다. 그 반대라면 다중 프로젝트 빌드가 실행됩니다.

이 동작의 목적은 무엇일까요? Gradle은 현재 있는 프로젝트가 다중 프로젝트 빌드의 하위 프로젝트인지 여부를 확인해야 합니다. 물론 하위 프로젝트라면 하위 프로젝트와 종속 프로젝트만 빌드되지만 Gradle은 전체 다중 프로젝트 빌드에 대한 빌드 구성을 생성해야 합니다. 현재 프로젝트에 settings.gradle 파일이 포함되어 있으면 빌드는 항상 다음과 같이 실행됩니다.

  • settings.gradle 파일이 다중 프로젝트 계층 구조를 정의하지 않는 경우 단일 프로젝트 빌드
  • settings.gradle 파일이 다중 프로젝트 계층 구조를 정의하는 경우 다중 프로젝트 빌드

settings.gradle 파일에 대한 자동 검색은 프로젝트 경로가 디스크의 실제 하위 프로젝트 레이아웃과 일치하는 기본 프로젝트 레이아웃이 있는 다중 프로젝트 빌드에서만 작동합니다. Gradle은 다중 프로젝트 빌드를 위한 임의의 물리적 레이아웃을 지원하지만 이러한 임의 레이아웃의 경우 설정 파일이 있는 디렉터리에서 빌드를 실행해야 합니다.

Gradle은 빌드에 참여하는 모든 프로젝트에 대해 Project 객체를 생성합니다. 다중 프로젝트 빌드의 경우 설정 개체(루트 프로젝트 포함)에 지정된 프로젝트입니다. 각 프로젝트 개체는 기본적으로 최상위 디렉터리의 이름과 동일한 이름을 가지며 루트 프로젝트를 제외한 모든 프로젝트에는 상위 프로젝트가 있습니다. 모든 프로젝트에는 하위 프로젝트가 있을 수 있습니다.

Configuration and execution of a single project build

단일 프로젝트 빌드의 경우 초기화 후 단계의 워크플로는 매우 간단합니다. 빌드 스크립트는 초기화 단계에서 생성된 프로젝트 개체에 대해 실행됩니다. 그런 다음 Gradle은 명령줄 인수로 전달된 것과 동일한 이름을 가진 작업을 찾습니다. 이러한 작업 이름이 있는 경우 전달한 순서대로 별도의 빌드로 실행됩니다.

Responding to the lifecycle in the build script

빌드 스크립트는 빌드가 수명 주기를 통해 진행됨에 따라 알림을 받을 수 있습니다. 이러한 알림은 일반적으로 두 가지 형식을 취합니다. 특정 수신기 인터페이스를 구현하거나 알림이 실행될 때 실행할 클로저를 제공할 수 있습니다. 아래 예제에서는 클로저를 사용합니다.

Project evaluation

프로젝트 평가 전후에 바로 알림을 받을 수 있습니다. 이것은 빌드 스크립트의 모든 정의가 적용된 후 추가 구성을 수행하거나 일부 사용자 지정 로깅 또는 프로파일링을 수행하는 데 사용할 수 있습니다.

다음은 hasTests 속성 값이 true인 각 프로젝트에 test 작업을 추가하는 예입니다.

  • build.gradle
allprojects {
    afterEvaluate { project ->
        if (project.hasTests) {
            println "Adding test task to $project"
            project.task('test') {
                doLast {
                    println "Running tests for $project"
                }
            }
        }
    }
}
  • project-a.gradle
hasTests = true
  • gradle -q test의 출력
> gradle -q test
Adding test task to project ':project-a'
Running tests for project ':project-a'

이 예제에서는 Project.afterEvaluate() 메서드를 사용하여 프로젝트가 평가된 후 실행되는 클로저를 추가합니다.

프로젝트가 평가될 때 알림을 받는 것도 가능합니다. 이 예는 프로젝트 평가의 일부 사용자 지정 로깅을 수행합니다. 프로젝트가 성공적으로 평가되었는지 여부에 관계없이 afterProject 알림이 수신된다는 점에 유의하세요.

  • build.gradle
gradle.afterProject { project ->
    if (project.state.failure) {
        println "Evaluation of $project FAILED"
    } else {
        println "Evaluation of $project succeeded"
    }
}
  • gradle -q test의 출력
> gradle -q test
Evaluation of root project 'build-project-evaluate-events' succeeded
Evaluation of project ':project-a' succeeded
Evaluation of project ':project-b' FAILED

FAILURE: Build failed with an exception.

* Where:
Build file '/home/user/gradle/samples/project-b.gradle' line: 1

* What went wrong:
A problem occurred evaluating project ':project-b'.
> broken

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 0s

Task creation

프로젝트에 작업이 추가된 직후 알림을 받을 수 있습니다. 이것은 빌드 파일에서 작업을 사용할 수 있게 되기 전에 일부 기본값을 설정하거나 동작을 추가하는 데 사용할 수 있습니다.

다음 예제에서는 생성될 때 각 작업의 srcDir 속성을 설정합니다.

  • build.gradle
tasks.whenTaskAdded { task ->
    task.ext.srcDir = 'src/main/java'
}

tasks.register('a')

println "source dir is $a.srcDir"
  • gradle -q a의 출력
> gradle -q a
source dir is src/main/java

Task execution graph ready

작업 실행 그래프가 채워진 직후 알림을 받을 수 있습니다.

Task execution

작업이 실행되기 직전과 직후에 알림을 받을 수 있습니다.

다음 예에서는 각 작업 실행의 시작과 끝을 기록합니다. 작업이 성공적으로 완료되었는지 또는 예외와 함께 실패했는지 여부에 관계없이 afterTask 알림이 수신됩니다.

  • build.gradle
tasks.register('ok')

tasks.register('broken') {
    dependsOn ok
    doLast {
        throw new RuntimeException('broken')
    }
}

gradle.taskGraph.beforeTask { Task task ->
    println "executing $task ..."
}

gradle.taskGraph.afterTask { Task task, TaskState state ->
    if (state.failure) {
        println "FAILED"
    }
    else {
        println "done"
    }
}
  • gradle -q broken의 출력
> gradle -q broken
executing task ':ok' ...
done
executing task ':broken' ...
FAILED

FAILURE: Build failed with an exception.

* Where:
Build file '/home/user/gradle/samples/build.gradle' line: 6

* What went wrong:
Execution failed for task ':broken'.
> broken

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 0s
profile
몰입을 즐기는 개발자입니다.

0개의 댓글