多组Protobuf生成独立Descriptor文件的Gradle构建配置问题
解决Gradle-Protobuf分目录生成独立Descriptor文件的方案
核心思路
Gradle官方protobuf插件默认会合并所有srcDir下的Proto文件生成单一Descriptor,要实现子目录独立生成.dsc,需要为每个子目录创建独立的protoc执行任务,绕过插件的默认合并逻辑。
具体配置(Groovy DSL)
plugins { id 'com.google.protobuf' version '0.9.4' id 'java' } // 禁用默认的Java类生成任务(只保留Descriptor生成能力) protobuf { protoc { // 让Gradle自动下载protoc,无需手动安装 artifact = "com.google.protobuf:protoc:3.25.3" } generateProtoTasks { all().each { task -> task.builtins.remove java } } } // 遍历descriptors目录下的所有子文件夹,生成独立任务 def descriptorsRoot = file('descriptors') descriptorsRoot.eachDir { subDir -> def taskName = "generate${subDir.name.capitalize()}Descriptor" def outputDsc = file("${buildDir}/descriptors/${subDir.name}.dsc") task(taskName, type: Exec) { commandLine protocExecutable, "--descriptor_set_out=${outputDsc.absolutePath}", "--proto_path=${descriptorsRoot.absolutePath}", // 若有公共依赖的Proto目录,可追加--proto_path参数 // "--proto_path=${file('common-protos').absolutePath}", subDir.listFiles({ f -> f.name.endsWith('.proto') } as FileFilter).collect { it.absolutePath } // 配置增量构建:仅当子目录Proto文件变化时重新执行 outputs.file outputDsc inputs.dir subDir } // 将自定义任务绑定到build生命周期 build.dependsOn taskName } // 获取插件下载的protoc可执行文件路径(避免手动指定) def getProtocExecutable() { return tasks.named('protoc').get().executable.path }
具体配置(Kotlin DSL)
plugins { id("com.google.protobuf") version "0.9.4" java } protobuf { protoc { artifact = "com.google.protobuf:protoc:3.25.3" } generateProtoTasks { all().forEach { task -> task.builtins.remove("java") } } } val descriptorsRoot = file("descriptors") descriptorsRoot.listFiles { file -> file.isDirectory }?.forEach { subDir -> val taskName = "generate${subDir.name.replaceFirstChar { it.uppercase() }}Descriptor" val outputDsc = file("${layout.buildDirectory.get()}/descriptors/${subDir.name}.dsc") tasks.register<Exec>(taskName) { val protocPath = tasks.named<Exec>("protoc").get().executable.path commandLine( protocPath, "--descriptor_set_out=${outputDsc.absolutePath}", "--proto_path=${descriptorsRoot.absolutePath}", *subDir.listFiles { f -> f.name.endsWith(".proto") }!!.map { it.absolutePath }.toTypedArray() ) outputs.file(outputDsc) inputs.dir(subDir) } tasks.named("build") { dependsOn(taskName) } }
关键说明
- 独立任务隔离:每个子目录对应一个
generateXXXDescriptor任务,单独调用protoc生成专属.dsc文件,彻底避免合并导致的类名冲突和依赖问题。 - 增量构建支持:通过
inputs.dir和outputs.file配置,Gradle会自动检测Proto文件变化,仅重新生成修改目录对应的Descriptor。 - protoc自动管理:无需手动安装protoc,插件会自动下载指定版本的可执行文件,保证环境一致性。
内容的提问来源于stack exchange,提问作者Styp
相关产品推荐
相关产品推荐

