1plugins { 2 id "cpp" 3 id "java" 4 id "maven-publish" 5 6 id "com.google.protobuf" 7} 8 9description = 'The protoc plugin for gRPC Java' 10 11def artifactStagingPath = "$buildDir/artifacts" as File 12// Adds space-delimited arguments from the environment variable env to the 13// argList. 14def addEnvArgs = { env, argList -> 15 def value = System.getenv(env) 16 if (value != null) { 17 value.split(' +').each() { it -> argList.add(it) } 18 } 19} 20 21// Adds corresponding "-l" option to the argList if libName is not found in 22// LDFLAGS. This is only used for Mac because when building for uploadArchives 23// artifacts, we add the ".a" files directly to LDFLAGS and without "-l" in 24// order to get statically linked, otherwise we add the libraries through "-l" 25// so that they can be searched for in default search paths. 26def addLibraryIfNotLinked = { libName, argList -> 27 def ldflags = System.env.LDFLAGS 28 if (ldflags == null || !ldflags.contains('lib' + libName + '.a')) { 29 argList.add('-l' + libName) 30 } 31} 32 33def String arch = rootProject.hasProperty('targetArch') ? rootProject.targetArch : osdetector.arch 34def boolean vcDisable = rootProject.hasProperty('vcDisable') ? rootProject.vcDisable : false 35def boolean usingVisualCpp // Whether VisualCpp is actually available and selected 36 37model { 38 toolChains { 39 // If you have both VC and Gcc installed, VC will be selected, unless you 40 // set 'vcDisable=true' 41 if (!vcDisable) { 42 visualCpp(VisualCpp) { 43 // Prefer vcvars-provided environment over registry-discovered environment 44 def String vsDir = System.getenv("VSINSTALLDIR") 45 def String winDir = System.getenv("WindowsSdkDir") 46 if (vsDir != null && winDir != null) { 47 installDir = vsDir 48 windowsSdkDir = winDir 49 } 50 } 51 } 52 gcc(Gcc) { 53 target("ppcle_64") { 54 cppCompiler.executable = 'powerpc64le-linux-gnu-g++' 55 linker.executable = 'powerpc64le-linux-gnu-g++' 56 } 57 target("aarch_64") { 58 cppCompiler.executable = 'aarch64-linux-gnu-g++' 59 linker.executable = 'aarch64-linux-gnu-g++' 60 } 61 target("s390_64") { 62 cppCompiler.executable = 's390x-linux-gnu-g++' 63 linker.executable = 's390x-linux-gnu-g++' 64 } 65 target("loongarch_64") 66 } 67 clang(Clang) { 68 } 69 } 70 71 platforms { 72 x86_32 { architecture "x86" } 73 x86_64 { architecture "x86_64" } 74 ppcle_64 { architecture "ppcle_64" } 75 aarch_64 { architecture "aarch_64" } 76 s390_64 { architecture "s390_64" } 77 loongarch_64 { architecture "loongarch_64" } 78 } 79 80 components { 81 java_plugin(NativeExecutableSpec) { 82 if (arch in [ 83 'x86_32', 84 'x86_64', 85 'ppcle_64', 86 'aarch_64', 87 's390_64', 88 'loongarch_64' 89 ]) { 90 // If arch is not within the defined platforms, we do not specify the 91 // targetPlatform so that Gradle will choose what is appropriate. 92 targetPlatform arch 93 } 94 baseName "$protocPluginBaseName" 95 } 96 } 97 98 binaries { 99 all { 100 if (toolChain in Gcc || toolChain in Clang) { 101 cppCompiler.define("GRPC_VERSION", version) 102 cppCompiler.args "--std=c++0x" 103 addEnvArgs("CXXFLAGS", cppCompiler.args) 104 addEnvArgs("CPPFLAGS", cppCompiler.args) 105 if (osdetector.os == "osx") { 106 cppCompiler.args "-mmacosx-version-min=10.7", "-stdlib=libc++" 107 addLibraryIfNotLinked('protoc', linker.args) 108 addLibraryIfNotLinked('protobuf', linker.args) 109 } else if (osdetector.os == "windows") { 110 linker.args "-static", "-lprotoc", "-lprotobuf", "-static-libgcc", "-static-libstdc++", 111 "-s" 112 } else if (osdetector.arch == "ppcle_64") { 113 linker.args "-Wl,-Bstatic", "-lprotoc", "-lprotobuf", "-Wl,-Bdynamic", "-lpthread", "-s" 114 } else { 115 // Link protoc, protobuf, libgcc and libstdc++ statically. 116 // Link other (system) libraries dynamically. 117 // Clang under OSX doesn't support these options. 118 linker.args "-Wl,-Bstatic", "-lprotoc", "-lprotobuf", "-static-libgcc", 119 "-static-libstdc++", 120 "-Wl,-Bdynamic", "-lpthread", "-s" 121 } 122 addEnvArgs("LDFLAGS", linker.args) 123 } else if (toolChain in VisualCpp) { 124 usingVisualCpp = true 125 cppCompiler.define("GRPC_VERSION", version) 126 cppCompiler.args "/EHsc", "/MT" 127 if (rootProject.hasProperty('vcProtobufInclude')) { 128 cppCompiler.args "/I${rootProject.vcProtobufInclude}" 129 } 130 linker.args "libprotobuf.lib", "libprotoc.lib" 131 if (rootProject.hasProperty('vcProtobufLibs')) { 132 linker.args "/LIBPATH:${rootProject.vcProtobufLibs}" 133 } 134 } 135 } 136 } 137} 138 139configurations { 140 testLiteImplementation 141} 142 143dependencies { 144 testImplementation project(':grpc-protobuf'), 145 project(':grpc-stub'), 146 libraries.javax.annotation 147 testLiteImplementation project(':grpc-protobuf-lite'), 148 project(':grpc-stub'), 149 libraries.javax.annotation 150} 151 152sourceSets { 153 testLite { 154 proto { setSrcDirs(['src/test/proto']) } 155 } 156} 157 158tasks.named("compileTestJava").configure { 159 options.errorprone.excludedPaths = ".*/build/generated/source/proto/.*" 160} 161 162tasks.named("compileTestLiteJava").configure { 163 options.compilerArgs = compileTestJava.options.compilerArgs 164 options.compilerArgs += [ 165 "-Xlint:-cast" 166 ] 167 options.errorprone.excludedPaths = ".*/build/generated/source/proto/.*" 168} 169 170tasks.named("checkstyleTestLite").configure { 171 enabled = false 172} 173 174protobuf { 175 protoc { 176 if (project.hasProperty('protoc')) { 177 path = project.protoc 178 } else { 179 artifact = libs.protobuf.protoc.get() 180 } 181 } 182 plugins { 183 grpc { path = javaPluginPath } 184 } 185 generateProtoTasks { 186 all().configureEach { 187 dependsOn 'java_pluginExecutable' 188 inputs.file javaPluginPath 189 } 190 ofSourceSet('test').configureEach { 191 plugins { grpc {} } 192 } 193 ofSourceSet('testLite').configureEach { 194 builtins { 195 java { option 'lite' } 196 } 197 plugins { 198 grpc { option 'lite' } 199 } 200 } 201 } 202} 203 204println "*** Building codegen requires Protobuf version ${libs.versions.protobuf.get()}" 205println "*** Please refer to https://github.com/grpc/grpc-java/blob/master/COMPILING.md#how-to-build-code-generation-plugin" 206 207tasks.register("buildArtifacts", Copy) { 208 dependsOn 'java_pluginExecutable' 209 from("$buildDir/exe") { 210 if (osdetector.os != 'windows') { 211 rename 'protoc-gen-grpc-java', '$0.exe' 212 } 213 } 214 into artifactStagingPath 215} 216 217archivesBaseName = "$protocPluginBaseName" 218 219def checkArtifacts = tasks.register("checkArtifacts") { 220 dependsOn buildArtifacts 221 doLast { 222 if (!usingVisualCpp) { 223 def ret = exec { 224 executable 'bash' 225 args 'check-artifact.sh', osdetector.os, arch 226 } 227 if (ret.exitValue != 0) { 228 throw new GradleException("check-artifact.sh exited with " + ret.exitValue) 229 } 230 } else { 231 def exeName = "$artifactStagingPath/java_plugin/${protocPluginBaseName}.exe" 232 def os = new ByteArrayOutputStream() 233 def ret = exec { 234 executable 'dumpbin' 235 args '/nologo', '/dependents', exeName 236 standardOutput = os 237 } 238 if (ret.exitValue != 0) { 239 throw new GradleException("dumpbin exited with " + ret.exitValue) 240 } 241 def dlls = os.toString() =~ /Image has the following dependencies:\s+(.*)\s+Summary/ 242 if (dlls[0][1] != "KERNEL32.dll") { 243 throw new Exception("unexpected dll deps: " + dlls[0][1]); 244 } 245 os.reset() 246 ret = exec { 247 executable 'dumpbin' 248 args '/nologo', '/headers', exeName 249 standardOutput = os 250 } 251 if (ret.exitValue != 0) { 252 throw new GradleException("dumpbin exited with " + ret.exitValue) 253 } 254 def machine = os.toString() =~ / machine \(([^)]+)\)/ 255 def expectedArch = [x86_32: "x86", x86_64: "x64"][arch] 256 if (machine[0][1] != expectedArch) { 257 throw new Exception("unexpected architecture: " + machine[0][1]); 258 } 259 } 260 } 261} 262 263// Exe files are skipped by Maven by default. Override it. 264// Also skip jar files that is generated by the java plugin. 265publishing { 266 publications { 267 maven(MavenPublication) { 268 // Removes all artifacts since grpc-compiler doesn't generates any Jar 269 artifacts = [] 270 artifactId 'protoc-gen-grpc-java' 271 artifact("$artifactStagingPath/java_plugin/${protocPluginBaseName}.exe" as File) { 272 classifier osdetector.os + "-" + arch 273 extension "exe" 274 builtBy checkArtifacts 275 } 276 pom.withXml { 277 // This isn't any sort of Java archive artifact, and OSSRH doesn't enforce 278 // javadoc for 'pom' packages. 'exe' would be a more appropriate packaging 279 // value, but it isn't clear how that will be interpreted. In addition, 280 // 'pom' is typically the value used when building an exe with Maven. 281 asNode().project.packaging*.value = 'pom' 282 } 283 } 284 } 285} 286 287def configureTestTask(Task task, String dep, String extraPackage, String serviceName) { 288 test.dependsOn task 289 task.dependsOn "generateTest${dep}Proto" 290 if (osdetector.os != 'windows') { 291 task.executable "diff" 292 task.args "-u" 293 } else { 294 task.executable "fc" 295 } 296 // File isn't found on Windows if last slash is forward-slash 297 def slash = System.getProperty("file.separator") 298 task.args "$buildDir/generated/source/proto/test${dep}/grpc/io/grpc/testing/compiler${extraPackage}${slash}${serviceName}Grpc.java", 299 "$projectDir/src/test${dep}/golden/${serviceName}.java.txt" 300} 301 302tasks.register("testGolden", Exec) { 303 configureTestTask(it, '', '', 'TestService') 304} 305tasks.register("testLiteGolden", Exec) { 306 configureTestTask(it, 'Lite', '', 'TestService') 307} 308tasks.register("testDeprecatedGolden", Exec) { 309 configureTestTask(it, '', '', 'TestDeprecatedService') 310} 311tasks.register("testDeprecatedLiteGolden", Exec) { 312 configureTestTask(it, 'Lite', '', 'TestDeprecatedService') 313} 314