使用Gradle简单编译Protobuf

29

如果您正在寻找Gradle Protobuf示例项目,请在此处查看。

我在处理Gradle和Protobuf方面遇到了困难,我想创建一个简单的Gradle项目,将默认的src/main/protosrc/test/proto中的任何Proto文件编译为相应的src/main/javasrc/test/java,然后打包成一个jar并发布到本地仓库。

不幸的是,我还不熟悉Gradle,并且无法理解原始项目的结构。

这是我的未完成的build.gradle文件:

apply plugin: 'java'
apply plugin: "com.google.protobuf"

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.7.0'
    }
}

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.google.protobuf:protobuf-java:3.0.0-beta-1'
}

sourceSets {
    main {
        proto {
            srcDir 'src/main/proto'
        }
        java {
            srcDir 'src/main/java'
        }
    }
    test {
        proto {
            srcDir 'src/test/proto'
        }
        proto {
            srcDir 'src/test/java'
        }
    }
}

protobuf {
    // Configure the protoc executable
    protoc {
        // Download from repositories
        artifact = 'com.google.protobuf:protoc:3.0.0-alpha-3'
    }
    generateProtoTasks {
        // all() returns the collection of all protoc tasks
        all().each { task ->
            // Here you can configure the task
        }

        // In addition to all(), you may get the task collection by various
        // criteria:

        // (Java only) returns tasks for a sourceSet
        ofSourceSet('main')

    }
}

运行jar任务后我们得到:

enter image description here

正如您所看到的,Gradle将测试和主要proto文件构建到同一个类目录中(红色箭头),在jar包中,我可以看到包括了生成的所有类(尽管测试应该被跳过)。

但主要问题是我想要直接将编译proto文件到适当的源目录(蓝色箭头),之后普通的构建就会做正确的事情...毕竟我们需要这些类在业务逻辑中使用...

因此,我们只需要一个任务来将proto编译到适当的源目录中...仅此而已。

src/main/proto to src/main/java
src/test/proto to src/test/java

当前项目所在地为这里。请帮忙配置,我相信以后会有很多人需要它...


你能分享一个可运行的例子吗?我知道它可能是未完成的。 - Opal
@Opal 我会把最终可用的版本留在这里,供其他人使用。https://github.com/vach/sample-gradle-protobuf - vach
你可以看一下这个例子 https://github.com/google/protobuf-gradle-plugin/blob/master/testProject/build.gradle - SubOptimal
1
@vach,请看一下这行代码:https://github.com/google/protobuf-gradle-plugin/blob/master/src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy#L86。由于proto任务是在“afterEvaluate”中添加的,因此您在“gradle tasks”输出中看不到这些任务-但它们确实存在。运行“gradlew generateProto”,并调查“build”目录。源代码将被生成。 - Opal
好的。我会看一下,但需要几个小时后才能给你答复。 - Opal
显示剩余8条评论
1个回答

27

如果我没有误解您的问题,那么解决起来很简单。如果您不想区分自己的源代码和生成的源代码,只需像这样设置generatedFileBaseDir即可:generateProtoTasks.generatedFilesBaseDir = 'src'

因此,整个构建文件如下:

// ...

protobuf {
// Configure the protoc executable
protoc {
    // Download from repositories
    artifact = 'com.google.protobuf:protoc:3.0.0-alpha-3'
}

generateProtoTasks.generatedFilesBaseDir = 'src' // <- that line 

generateProtoTasks {
    // all() returns the collection of all protoc tasks
    all().each { task ->
        // Here you can configure the task
    }

你的文件夹看起来像这样:

  • src/main/java/com/vach/tryout/AddressBookProtos.java
  • src/main/java/com/vach/tryout/protobuf/Main.java

但是:可能将生成的代码与手工编写的源代码混合在一起并不是最好的想法。因此,我的建议是将生成的源代码放入一个名为generatedSources的单独目录中,并将该目录添加到java sourceSet中。构建文件应如下所示:

sourceSets {
    main {
        proto {
            srcDir 'src/main/proto'
        }
        java {
            // include self written and generated code
            srcDirs 'src/main/java', 'generated-sources/main/java'            
        }
    }
    // remove the test configuration - at least in your example you don't have a special test proto file
}

protobuf {
    // Configure the protoc executable
    protoc {
        // Download from repositories
        artifact = 'com.google.protobuf:protoc:3.0.0-alpha-3'
    }

    generateProtoTasks.generatedFilesBaseDir = 'generated-sources'

    generateProtoTasks {
        // all() returns the collection of all protoc tasks
        all().each { task ->
            // Here you can configure the task
        }

        // In addition to all(), you may get the task collection by various
        // criteria:

        // (Java only) returns tasks for a sourceSet
        ofSourceSet('main')

    }   
}

您的目录将如下所示:
  • src/main/proto/dtos.proto
  • src/main/java/com/vach/tryout/protobuf/Main.java
  • generated-sources/main/java/com/vach/tryout/AddressBookProtos.java
一个好的副作用是,您可以在git配置中忽略这个generated-sources目录。这总是一个好主意,不要发布生成的源代码。

我不太明白为什么将生成的代码放在手工编写的代码旁边被认为是不好的,即使默认行为将它们分开到不同的目录中...毕竟,protobuf是一种用于生成高效序列化和反序列化DTO的工具,而且您将在手工编写的代码中使用它们...如果您将它们分开放置到不同的目录中,就需要配置IDE来知道有关其他源目录的信息...我真的没有看到足够好的理由去这样做... - vach
我打算使用protobuf的方式是创建一个小项目,其中包含所有的DTOs,并将dtos.jar暴露到本地仓库中,其他项目可以使用它... - vach
关于你的第一个问题 - 为什么要将生成的代码与“编写的代码”分开:这确实是一种口味问题。您可以在此处找到讨论:[https://dev59.com/0XNA5IYBdhLWcg3wmfO5]。除了具有较小的提交外,某些人可能会意外更改生成的代码。此外,删除类型将变得更加困难(您必须删除原型文件和Java文件)。 - TobiSH
所以实现这个功能的方式是在某个其他目录(不包括VCS)中生成代码,但要在本地环境中可见。然后,任何检出代码的开发人员都将通过proto文件获取更新并自行构建它?希望我表述得正确?我想这也可以立即检测到生成代码中的任何意外手写更改... - vach
1
@vach,我不明白你的问题 - 也许你可以更新一下你的Github项目(或者接受我的拉取请求)。 - TobiSH
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接