web-dev-qa-db-ja.com

単一のソースフォルダーから複数のjarをGradle

今のところ、srcという名前の単一のソースフォルダーを持つプロジェクト構造があり、3つのモジュールのソースコードが含まれています。私がやりたいことは:

1)ソースコードをコンパイルします。これは、sourceSets定義を使用して簡単に実行できます。

sourceSets {
    main {
        Java {
            srcDir 'src'
        }
    }
}

2)コンパイル結果を3つのjarに入れます。私は3つの「jar」タイプのタスクを介してこれを行っています:

私は今、3つの個別のタスクを介してこれを行っています。

  • util.jar

    task utilJar(type: Jar) {
        from(sourceSets.main.output) {
            include "my/util/package/**"
        }
    }
    
  • client.jar

    task clientJar(type: Jar) {
        from(sourceSets.main.output) {
            include "my/client/package/**"
        }
    }
    
  • server.jar

    task serverJar(type: Jar) {
        from(sourceSets.main.output) {
            include "**"
        }
        excludes.addAll(utilJar.includes)
        excludes.addAll(clientJar.includes)
    }
    

問題は、server.jarにはclient.jarおよびutil.jarに含まれていないすべてのクラスが含まれている必要があるということです。 antビルドスクリプトでは、difference antタスクを使用してこの問題を解決します。これをgradleでどのように行うことができますか(私の現在のアプローチは機能しません)?

たぶん私のアプローチは完全に間違っています。ご意見をお聞かせください。

追伸今のところ、プロジェクトのソースコードのフォルダー構造を変更することはできません。

34
vitalidze

答えとしてここに作業中のソリューションを投稿します(gradleのフォーラムにヒントがあります)。

Gradleのスコープは非常に奇妙です:)すべてのタスク定義は、この特定のケースでは「JarTask」のような「Task」クラスのオブジェクトを作成すると思いました。その後、build.gradleスクリプトのどこからでもクラスのプロパティにアクセスできます。ただし、jarファイルに含まれるパターンを確認できる唯一の場所は、タスクのfromブロック内です。したがって、今のところ私の作業ソリューションは次のとおりです。

1)server.jarから除外されるパターンを含むプロジェクトレベルのコレクションを定義します

2)fromタスクのserverJarブロック内のすべてのパターンを除外します。

以下の最終版をご覧ください

sourceSets {  
    main {  
        Java {  
            srcDir 'src'  
        }  
    }  
} 

// holds classes included into client.jar and util.jar, so they are to be excluded from server.jar
ext.serverExcludes = []

// util.jar
task utilJar(type: Jar) {  
    from(sourceSets.main.output) {  
        include "my/util/package/**" 
        project.ext.serverExcludes.addAll(includes)
    }  
}

// client.jar
task clientJar(type: Jar) {  
    from(sourceSets.main.output) {  
        include "my/client/package/**"
        project.ext.serverExcludes.addAll(includes)
    }  
}

// server.jar
task serverJar(type: Jar) {  
    from(sourceSets.main.output) {  
        exclude project.ext.serverExcludes
    }  
}
30
vitalidze

アプローチが間違っていると思います。 3つのサブプロジェクトでプロジェクトを作成することをお勧めします。

project
- util
- server (depends on util)
- client (depends on util)

何らかの理由でクラス構造を変更できない場合は、次の種類のビルドファイルを使用します。

settings.gradle

include 'util', 'client', 'server'

build.gradle

subprojects {
    apply plugin: 'Java'
}

project(':util') {
    sourceSets {
        main {
            Java {
                srcDir '../src'
                include 'util/**'
            }
        }
    }
}

project(':server') {
    sourceSets {
        main {
            Java {
                srcDir '../src'
                include 'server/**'
            }
        }
    }
    dependencies {
        compile project(':util')
    }
}

project(':client') {
    sourceSets {
        main {
            Java {
                srcDir '../src'
                include 'client/**'
            }
        }
    }
    dependencies {
        compile project(':util')
    }
}

サブプロジェクトにはまだディレクトリが必要ですが、ソースは必要に応じて1か所にあります。

gradle assembleを実行すると、個別のクラスセットを持つ3つのjarが作成されます。このソリューションの利点は、jarを作成するためのタスクだけでなく、正しい依存関係を持つ適切なGradleマルチモジュールプロジェクトを作成できることです。

Multi-Project Builds をお読みください。

23
Grzegorz Żur

私の会社でも同じ問題があります。 「良い」プロジェクト構造に移行するのが難しいレガシーコード、および同じコードベースから複数のjarを構築する必要性。異なるsourceSetを定義し、標準のGradleを使用して各sourceSetをビルドすることにしました。

次に、イテレータを使用して、各sourceSetのjarタスクとjavadocタスクを追加します。

sourceSets.all { SourceSet sourceSet ->
    Task jarTask = tasks.create("jar" + sourceSet.name, Jar.class)
    jarTask.from(sourceSet.output)
    // Configure other jar task properties: group, description, manifest etc

    Task javadocTask = tasks.create("javadoc" + sourceSet.name, Javadoc.class)
    javadocTask.setClasspath(sourceSet.output + sourceSet.compileClasspath)
    javadocTask.setSource(sourceSet.allJava)
    // Extra config for the javadoc task: group, description etc

    Task javadocJarTask = tasks.create("javadocJar" + sourceSet.name, Jar.class)
    javadocJarTask.setClassifier("javadoc") // adds "-javadoc" to the name of the jar
    javadocJarTask.from(javadocTask.outputs)
    // Add extra config: group, description, manifest etc
}
4
JonasOhrnell

私も原則として受け入れられた答えに同意します。マニフェストがClass-Pathキーによってのみ異なることを除き、クライアントが本質的に同じファイルの2つのJARを必要とするプロジェクトを見つけました。

jar {
    manifest {
        attributes(
                "Main-Class": platformMainClass,
                "Implementation-Title": platformDisplayName,
                "Implementation-Description": platformDescription,
                "Platform-Version": platformVersion,
                "Implementation-Version": version,
                "Build-Assembly-User": System.getProperty("user.name"),
                "Build-Assembly-Date": new Java.util.Date().toString(),
                "Class-Path": configurations.compile.collect { "lib/"+it.getName() }.join(' ')
        )
    }

    duplicatesStrategy = DuplicatesStrategy.EXCLUDE

    exclude( [ 'log4j*.properties', 'uk/gov/acme/secret/product/server/**' ])
}

同じマニフェストとソースコードは次のとおりです。

task applicationClientJar(type: Jar, description: "Creates the Application  Client JAR file.") {
    dependsOn compileJava
    manifest {
        attributes(
                "Main-Class": platformMainClass,
                "Implementation-Title": platformDisplayName,
                "Implementation-Description": platformDescription,
                "Platform-Version": platformVersion,
                "Implementation-Version": version,
                "Assembly-Date": new Java.util.Date().toString()
        )
    }
    archiveName = "acme-client-${platformVersion}.jar"
    destinationDir = file("${buildDir}/libs")
    from sourceSets.main.output

    duplicatesStrategy = DuplicatesStrategy.EXCLUDE

    exclude( [ 'log4j*.properties', 'uk/gov/acme/secret/product/server/**'     }

Grzegorz表記は正しいです。Gradleは、GAVを持つ2つの異なるJARがあることを知っているはずです。マルチモジュールが推奨されるオプションです。

compile "uk.gov.acme.secret:acme:1.0"  // CORE
compile "uk.gov.acme.secret:acme-client:1.0"

これを設定する唯一の方法は、Multi-Module Gradleプロジェクトを使用してから、コア/メインプロジェクトにコンパイルおよび/またはデプロイの依存関係を追加することです。

project(':common:acme-micro-service-webapp') {
    dependencies {
        compile project(':common:acme-core')
    }
}

「acme-micro-service-webapp」プロジェクト内では、これにより、依存する「common:acme-core」が最初にコンパイルされます。

PS:私はまだより良い解決策を見つけようとしています。

PS PS:Mavenも使用している場合は、「インストール」タスクをフックすることができます。

2
peter_pilgrim