사용자 도구

사이트 도구


gradle:multiproject

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

양쪽 이전 판 이전 판
다음 판
이전 판
gradle:multiproject [2012/10/05 20:20]
kwon37xi [실전 예제]
gradle:multiproject [2022/07/06 10:20] (현재)
kwon37xi [서브 프로젝트간 의존성]
줄 2: 줄 2:
   * [[http://www.gradle.org/docs/current/userguide/multi_project_builds.html|Gradle Multi Project Builds]]   * [[http://www.gradle.org/docs/current/userguide/multi_project_builds.html|Gradle Multi Project Builds]]
   * [[http://gradle.org/docs/current/dsl/org.gradle.api.Project.html|Project]] DSL 참조.   * [[http://gradle.org/docs/current/dsl/org.gradle.api.Project.html|Project]] DSL 참조.
 +
 +====== 최상위 프로젝트의 이름 ======
 +''settings.gradle'' 파일에서 다음과 같이 최상위 프로젝트 이름을 지정한다. 이는 해당 프로젝트 디렉토리 이름과 무관하게 설정된다.
 +<code>
 +rootProject.name = '프로젝트이름'
 +</code>
  
 ===== 멀티 프로젝트의 기본 ===== ===== 멀티 프로젝트의 기본 =====
줄 36: 줄 42:
 } }
 // shared 서브 프로젝트에 의존하고 있다. // shared 서브 프로젝트에 의존하고 있다.
 +</code>
 +
 +==== build.gradle 대신 subproject 이름으로 gradle 파일 구성 ====
 +  * 멀티 모듈 프로젝트를 구성하면 지나치게 많은 ''build.gradle'' 파일 때문에 혼란스러워진다.
 +  * 아래와 같이 ''settings.gradle'' 에 설정하여 각각의 sub module 들에 대한 설정 파일을 ''submodule-name.gradle''로 변경할 수 있다.
 +
 +<code groovy>
 +rootProject.children.each {project ->
 +    project.buildFileName = "${project.name}.gradle"
 +}
 </code> </code>
  
줄 159: 줄 175:
 </code> </code>
  
-==== 프로젝트 필터링 ====+==== 프로젝트 필터링 Filter Projects ====
 ''tropicalFish''라는 프로젝트를 추가하고 ''water'' 프로젝트 빌드 파일에 행위를 더 추가해보자. ''tropicalFish''라는 프로젝트를 추가하고 ''water'' 프로젝트 빌드 파일에 행위를 더 추가해보자.
 +
 +=== 명시하기 ===
 +<code>
 +def projects = [project('project-name'), project('project-name-2')]
 +
 +// 특정 프로젝트들에 대한 설정..
 +configure(projects) {
 +    ....
 +}
 +</code>
  
 === 이름으로 필터링 === === 이름으로 필터링 ===
줄 476: 줄 502:
   * 하지만 실행시 의존성은 webDist가 date와 hello의 빌드된 아티팩트에 의존한다.   * 하지만 실행시 의존성은 webDist가 date와 hello의 빌드된 아티팩트에 의존한다.
   * 세번째 의존성으로 webDist가 자식인 date와 hello에 구성시 의존성도 있는데, 이는 ''arhivePath''를 알아야만 하기 때문이다. 하지만 태스크를 실행하는 시점에 요청한다. 따라서 순환 의존성은 아니다.   * 세번째 의존성으로 webDist가 자식인 date와 hello에 구성시 의존성도 있는데, 이는 ''arhivePath''를 알아야만 하기 때문이다. 하지만 태스크를 실행하는 시점에 요청한다. 따라서 순환 의존성은 아니다.
 +  * [[http://www.gradle.org/docs/current/groovydoc/org/gradle/api/DomainObjectCollection.html#withType%28java.lang.Class%29|withType()]] 메소드. 컬렉션에서 특정 타입인 것만 골라서 새로운 컬렉션으로 만든다.
 +
 +===== 프로젝트 lib 의존성 =====
 +한 프로젝트가 다른 프로젝트의 컴파일 결과와 그 의존하는 라이브러리들 모두에 의존하는 경우가 발생한다. 이 때 프로젝트간 의존성을 설정한다.
 +
 +  * 프로젝트 레이아웃<code>
 +java/
 +  settings.gradle
 +  build.gradle
 +  api/
 +    src/main/java/
 +      org/gradle/sample/
 +        api/
 +          Person.java
 +        apiImpl/
 +          PersonImpl.java
 +  services/personService/
 +    src/
 +      main/java/
 +        org/gradle/sample/services/
 +          PersonService.java
 +      test/java/
 +        org/gradle/sample/services/
 +          PersonServiceTest.java
 +  shared/
 +    src/main/java/
 +      org/gradle/sample/shared/
 +        Helper.java
 +</code>
 +  * shared, api, personService 프로젝트가 있다. personService는 다른 두 프로젝트에 의존하고, api는 shared에 의존한다.
 +  * ''settinga.gradle'' <code groovy>
 +include 'api', 'shared', 'services:personService'
 +</code>
 +  * ''build.gradle'' <code groovy>
 +subprojects {
 +    apply plugin: 'java'
 +    group = 'org.gradle.sample'
 +    version = '1.0'
 +    repositories {
 +        mavenCentral()
 +    }
 +    dependencies {
 +        testCompile "junit:junit:4.8.2"
 +    }
 +}
 +
 +project(':api') {
 +    dependencies {
 +        compile project(':shared')
 +    }
 +}
 +
 +project(':services:personService') {
 +    dependencies {
 +        compile project(':shared'), project(':api')
 +    }
 +}
 +</code>
 +  * lib 의존성은 실행시 의존성의 특별한 형태이다. 의존성이 걸리게 되면 다른 프로젝트가 먼저 빌드하여 jar를 생성하고 그것을 현재 프로젝트의 클래스패스에 추가한다.
 +  * 따라서 api 디렉토리에서 ''gradle compile''을 실행하면 shared가 먼저 빌드 되고 그 뒤에 api가 빌드 된다. 프로젝트 의존성은 부분적인 멀티 프로젝트 빌드를 가능케 한다.
 +  * Ivy 방식의 매우 상세한 의존성 설정도 가능하다.
 +  * ''build.gradle'' <code groovy>
 +subprojects {
 +    apply plugin: 'java'
 +    group = 'org.gradle.sample'
 +    version = '1.0'
 +}
 +
 +project(':api') {
 +    configurations {
 +        spi
 +    }
 +    dependencies {
 +        compile project(':shared')
 +    }
 +    task spiJar(type: Jar) {
 +        baseName = 'api-spi'
 +        dependsOn classes
 +        from sourceSets.main.output
 +        include('org/gradle/sample/api/**')
 +    }
 +    artifacts {
 +        spi spiJar
 +    }
 +}
 +
 +project(':services:personService') {
 +    dependencies {
 +        compile project(':shared')
 +        compile project(path: ':api', configuration: 'spi')
 +        testCompile "junit:junit:4.8.2", project(':api')
 +    }
 +}
 +</code>
 +  * Java 플러그인은 기본적으로 프로젝트당 모든 클래스를 포함한 하나의 jar를 생성한다. 위 예제에서는 api 프로젝트의 인터페이스만 포함하는 추가적인 jar를 생성하였다.
 +
 +==== 의존하는 프로젝트의 빌드 금지하기 ====
 +  * 때로는 부분 빌드를 할 때 의존하고 있는 프로젝트를 빌드하지 않기를 바랄 때도 있다. ''-a'' 옵션으로 gradle을 실행하면 된다.
 +
 +===== 분리된(decoupled) 프로젝트 =====
 +  * 두 프로젝트간의 프로젝트 모델에 접근하지 않는 것을 서로 분리된(decoupled) 프로젝트라고 부른다.
 +  * 분리된 프로젝트는 프로젝트 의존성이나 태스크 의존성으로만 연결되어 있다.
 +  * 그 외의 어떠한 형태의 프로젝트간 소통행위( 다른 프로젝트의 값을 읽거나 수정하는 등)은 두 프로젝트를 엮인(coupled) 프로젝트로 만든다.
 +  * 엮인 프로젝트가 되는 가장 일반적인 상황은 교차 프로젝트 설정에서 구성 주입을 사용할 경우이다.
 +  * ''allprojects'' 혹은 ''subprojects'' 키워드를 사용한 순간 프로젝트들은 엮인 것이다.
 +
 +===== 멀티 프로젝트 빌드와 테스트 =====
 +  * Java 플러그인의 ''build'' 태스크를 사용하여 컴파일, 테스트, 코드 스타일 검사(CodeQuality 플러그인 사용시)등을 할 수 있다.
 +  * 다중 프로젝트에서 여러 범위의 프로젝트에 대해 빌드를 할 경우가 있는데 이 때 ''buildNeeded'' 와 ''buildDependents'' 태스크를 사용한다.
 +  * "프로젝트 lib 의존성"의 프로젝트로 테스트 해본다.
 +  * ''gradle :api:build'' : api와 api가 의존하는 모든 프로젝트에 대해 컴파일과 jar를 수행하고 api 프로젝트의 build를 수행한다.
 +  * ''gradle -a :api:build'' : api 프로젝트의 build만 수행한다.
 +  * ''gradle :api:buildNeeded'' : api와 api가 의존하는 모든 프로젝트의 build를 수행한다.
 +  * ''gradle :api:buildDependents'' : api와 api에 의존하는 모든 프로젝트에 대해 build를 수행한다.
 +  * ''gradle build'' : 모든 프로젝트에 대해 build한다.
 +
 +===== 프라퍼티와 메소드 상속 =====
 +  * 프로젝트에 정의된 프라퍼티와 메소드는 모든 서브 프로젝트로 상속된다.
 +  * 이 때문에 ''gradle 태스크이름 -P프라퍼티이름=값''으로 실행할 경우 모든 ''project'' 객체에서 해당 프라퍼티를 사용할 수 있게 된다.
 +
 +===== 멀티 프로젝트 단위 테스트간의 의존성 =====
 +  * 이제는 더이상 아래 방법을 사용하지 말고 [[gradle:testfixtures|TestFixtures]]를 통해 합리적으로 해결 가능해졌다.
 +<note warning>
 +아래 방법은 사용하지 말 것.
 +
 +테스트들 간의 의존성을 거는 것은 어쩔 수 없을때만한다.
 +
 +꼭 필요하다면 테스트를 위한 별도 모듈을 만들고 그에 대해 일반적인 의존을 하게 변경한다.
 +</note>
 +
 +개인적으로 아래 방법보다는 공통 단위 테스트용 프로젝트를 만들고(예: ''xxx-test-support'') 해당 프로젝트에 각종 테스트용 의존성과 테스트용 유틸리티 클래스를 일반 코드로 작성한 뒤에 다른 프로젝트들이 ''testCompile project(':xxx-test-support')'' 형태로 의존성을 추가하는 것이 더 일관성 있고 깔끔한 방법으로 보인다.
 +
 +----
 +
 +ProjectA와 ProjectB의 단위테스트가 존재하는데, ProjectB의 단위테스트가 ProjectA의 단위테스트 클래스 중 일부에 의존하고 있다면, 기본적으로는 클래스를 찾지 못해 예외가 발생한다.
 +단위 테스트는 프로젝트간 의존성에서 제외되기 때문이다.
 +[[http://stackoverflow.com/questions/5644011/multi-project-test-dependencies-with-gradle|build - Multi-project test dependencies with gradle]]에 해결책이 있으나 ''classes''가 write-only로 바뀌고 읽을 때는 ''output''을 하도록 바뀌었다.
 +
 +  * ProjectB의 ''build.gradle'' <code groovy>
 +dependencies {
 +    testCompile project(':projectA').sourceSets.test.output // projectA의 단위 테스트 클래스에 의존함.
 +    // 이 방법은 eclipse에서 projecA의 단위 테스트 디렉토리를 라이브러리로 등록하는 문제가 있음.
 +}
 +</code>
 +  * 위 방법보다는 configuration을 사용하는 다른 방법이 더 유용하다. [[gradle:eclipse|Gradle Ecplise Plugin]] 사용시 설정 필요 ''build.gradle'' <code groovy>
 +configurations {
 +    crosstest
 +    testCompile.extendsFrom crosstest  // testCompile이 crosstest에 의존하게 변경
 +}
 +
 +dependencies {
 +    crosstest project(':projectA').sourceSets.test.output
 +}
 +
 +eclipse {
 +    classpath {
 +        minusConfigurations += configurations.crosstest // 불필요한 classpath 등록 방지
 +    }
 +}
 +</code>
 +
 +===== 참조 =====
 +  * [[https://blog.sapzil.org/2018/06/20/gradle-subproject-grouping/|Gradle에서 서브 프로젝트를 한 디렉토리에 몰아넣기 | The Sapzil]]
 +
gradle/multiproject.1349436018.txt.gz · 마지막으로 수정됨: 2012/10/05 20:20 저자 kwon37xi