1description = 'Conscrypt: OpenJdk' 2 3ext { 4 jniSourceDir = "$rootDir/common/src/jni" 5 assert file("$jniSourceDir").exists() 6 7 // Build the list of classifiers that will be used in the build. 8 arch32Name = 'x86' 9 arch64Name = 'x86_64' 10 nativeClassifiers = [] 11 nativeClassifier64Bit = null 12 nativeClassifier32Bit = null 13 nativeConfiguration64Bit = null 14 nativeConfiguration32Bit = null 15 preferredNativeConfiguration = null 16 preferredClassifier = null 17 preferredSourceSet = null 18 preferredNativeFileDir = null 19 if (build64Bit) { 20 // Add the 64-Bit classifier first, as the preferred classifier. 21 nativeClassifier64Bit = classifierFor(osName, arch64Name) 22 nativeClassifiers += nativeClassifier64Bit 23 preferredClassifier = nativeClassifier64Bit 24 preferredSourceSet = sourceSetName(preferredClassifier) 25 preferredNativeFileDir = nativeResourcesDir(preferredClassifier) 26 27 nativeConfiguration64Bit = compileConfigurationName(nativeClassifier64Bit) 28 preferredNativeConfiguration = nativeConfiguration64Bit 29 } 30 if (build32Bit) { 31 nativeClassifier32Bit = classifierFor(osName, arch32Name) 32 nativeClassifiers += nativeClassifier32Bit 33 if (preferredClassifier == null) { 34 preferredClassifier = nativeClassifier32Bit 35 preferredSourceSet = sourceSetName(preferredClassifier) 36 preferredNativeFileDir = nativeResourcesDir(preferredClassifier) 37 } 38 39 nativeConfiguration32Bit = compileConfigurationName(nativeClassifier32Bit) 40 if (preferredNativeConfiguration == null) { 41 preferredNativeConfiguration = nativeConfiguration32Bit 42 } 43 } 44} 45 46sourceSets { 47 48 main { 49 java { 50 srcDirs += "${rootDir}/common/src/main/java" 51 srcDirs += project(':conscrypt-constants').sourceSets.main.java.srcDirs 52 } 53 } 54 55 platform { 56 java { 57 srcDirs = [ "src/main/java" ] 58 includes = [ "org/conscrypt/Platform.java" ] 59 } 60 } 61 62 test { 63 resources { 64 // This shouldn't be needed but seems to help IntelliJ locate the native artifact. 65 srcDirs += preferredNativeFileDir 66 } 67 } 68 69 // Add the source sets for each of the native build 70 nativeClassifiers.each { nativeClassifier -> 71 def sourceSetName = sourceSetName(nativeClassifier) 72 def testSourceSetName = testSourceSetName(nativeClassifier) 73 74 // Main sources for the native build 75 "$sourceSetName" { 76 resources { 77 srcDirs = [nativeResourcesDir(nativeClassifier)] 78 } 79 } 80 81 // Test sources for the native build 82 "${testSourceSetName}" { 83 java { 84 // Include the test source. 85 srcDirs = test.java.srcDirs 86 } 87 resources { 88 srcDirs = ["src/test/resources"] 89 srcDirs += sourceSets["$sourceSetName"].resources.srcDirs 90 } 91 } 92 } 93} 94 95task platformJar(type: Jar) { 96 from sourceSets.platform.output 97} 98 99if (isExecutableOnPath('cpplint')) { 100 task cpplint(type: Exec) { 101 executable = 'cpplint' 102 103 // TODO(nmittler): Is there a better way of getting the JNI sources? 104 def pattern = ['**/*.cc', '**/*.h'] 105 def sourceFiles = fileTree(dir: jniSourceDir, includes: pattern).asPath.tokenize(':') 106 // Adding roots so that class #ifdefs don't require full path from the project root. 107 args = sourceFiles 108 109 // Capture stderr from the process 110 errorOutput = new ByteArrayOutputStream(); 111 112 // Need to ignore exit value so that doLast will execute. 113 ignoreExitValue = true 114 115 doLast { 116 // Create the report file. 117 def reportDir = file("${buildDir}/cpplint") 118 reportDir.mkdirs(); 119 def reportFile = new File(reportDir, "report.txt") 120 def reportStream = new FileOutputStream(reportFile) 121 122 try { 123 // Check for failure 124 if (execResult != null) { 125 execResult.assertNormalExitValue() 126 } 127 } catch (Exception e) { 128 // The process failed - get the error report from the stderr. 129 String report = errorOutput.toString(); 130 131 // Write the report to the console. 132 System.err.println(report) 133 134 // Also write the report file. 135 reportStream.write(report.bytes); 136 137 // Extension method cpplint.output() can be used to obtain the report 138 ext.output = { 139 return report 140 } 141 142 // Rethrow the exception to terminate the build. 143 throw e; 144 } finally { 145 reportStream.close(); 146 } 147 } 148 } 149 check.dependsOn cpplint 150} 151 152configurations { 153 publicApiDocs 154 platform 155} 156 157artifacts { 158 platform platformJar 159} 160 161// Append the BoringSSL-Version to the manifest. 162jar.manifest { 163 attributes 'BoringSSL-Version' : boringSslVersion 164} 165 166dependencies { 167 // This is used for the @hide annotation processing in JavaDoc 168 publicApiDocs project(':conscrypt-api-doclet') 169 170 compileOnly project(':conscrypt-constants'), 171 configurations.publicApiDocs 172 173 testCompile project(':conscrypt-constants'), 174 project(':conscrypt-testing'), 175 libraries.junit, 176 libraries.mockito 177 178 // Need to add the native artifact to classpath when running the tests. 179 testRuntime configurations["${preferredNativeConfiguration}"] 180 181 // Configure the dependencies for the native tests. 182 nativeClassifiers.each { nativeClassifier -> 183 def testCompileConfigName = testSourceSet(nativeClassifier).compileConfigurationName 184 "${testCompileConfigName}" ( 185 sourceSets.main.output, // Explicitly add the main classes 186 project(':conscrypt-constants'), 187 project(':conscrypt-testing'), 188 libraries.junit, 189 libraries.mockito 190 ) 191 } 192 193 platformCompileOnly sourceSets.main.output 194} 195 196nativeClassifiers.each { nativeClassifier -> 197 // Create the JAR task and add it's output to the published archives for this project 198 addNativeJar(nativeClassifier) 199 200 // Create the test task and have it auto run whenever the test task runs. 201 addNativeTest(nativeClassifier) 202 203 // Build the classes as part of the standard build. 204 classes.dependsOn sourceSet(nativeClassifier).classesTaskName 205 testClasses.dependsOn testSourceSet(nativeClassifier).classesTaskName 206} 207 208// Adds a JAR task for the native library. 209def addNativeJar(nativeClassifier) { 210 // Create a JAR for this configuration and add it to the output archives. 211 SourceSet sourceSet = sourceSet(nativeClassifier) 212 def jarTaskName = sourceSet.jarTaskName 213 task "$jarTaskName"(type: Jar) { 214 // Depend on the regular classes task 215 dependsOn classes 216 manifest = jar.manifest 217 classifier = nativeClassifier 218 219 from sourceSet.output + sourceSets.main.output 220 } 221 222 def jarTask = tasks["$jarTaskName"] 223 224 // Add the jar task to the standard build. 225 jar.dependsOn jarTask 226 227 // Add it to the 'archives' configuration so that the artifact will be automatically built and 228 // installed/deployed. 229 artifacts.add('archives', jarTask) 230} 231 232// Optionally adds a test task for the given platform 233def addNativeTest(nativeClassifier) { 234 SourceSet testSourceSet = testSourceSet(nativeClassifier) 235 236 // Just use the same name as the source set for the task. 237 def testTaskName = "${testSourceSet.name}" 238 def javaExecutable 239 def javaArchFlag 240 if (testSourceSet.name.endsWith("${arch32Name}Test")) { 241 // 32-bit test 242 javaExecutable = javaExecutable32 != null ? javaExecutable32 : test.executable 243 javaArchFlag = '-d32' 244 } else { 245 // 64-bit test 246 javaExecutable = javaExecutable64 != null ? javaExecutable64 : test.executable 247 javaArchFlag = '-d64' 248 } 249 250 // Execute the java executable to see if it supports the architecture flag. 251 def javaError = new ByteArrayOutputStream() 252 exec { 253 System.out.println("Running tests with java executable: " + javaExecutable + ".") 254 executable javaExecutable 255 args = ["$javaArchFlag", '-version'] 256 ignoreExitValue true 257 errorOutput = javaError 258 } 259 260 // Only add the test if the javaArchFlag is supported for the selected JVM 261 def archSupported = !javaError.toString().toLowerCase().contains('error') 262 if (archSupported) { 263 task "$testTaskName"(type: Test) { 264 dependsOn testSourceSet.classesTaskName 265 jvmArgs javaArchFlag 266 executable = javaExecutable 267 testClassesDir = testSourceSet.output.classesDir 268 269 // TODO(nmittler): Is there a way to copy all properties of the test task? 270 271 // Copy the logging configuration from the test task. 272 org.codehaus.groovy.runtime.InvokerHelper.setProperties(testLogging, 273 test.testLogging.properties) 274 275 // Copy heap settings. 276 minHeapSize = test.minHeapSize 277 maxHeapSize = test.maxHeapSize 278 279 // Copy system properties 280 systemProperties = test.systemProperties 281 282 // Set the classpath just before we run the test so that the runtime classpath 283 // is fully resolved. 284 doFirst { 285 classpath = testSourceSet.runtimeClasspath 286 } 287 } 288 test.dependsOn "$testTaskName" 289 } 290} 291 292// Exclude all test classes from the default test suite. 293// We will test each available native artifact separately (see nativeClassifiers). 294test.exclude("**") 295 296javadoc { 297 options.doclet = "org.conscrypt.doclet.FilterDoclet" 298 options.docletpath = configurations.publicApiDocs.files as List 299} 300 301model { 302 platforms { 303 x86 { 304 architecture arch32Name 305 } 306 x86_64 { 307 architecture arch64Name 308 } 309 } 310 311 buildTypes { 312 release 313 } 314 315 components { 316 // Builds the JNI library. 317 conscrypt_openjdk_jni(NativeLibrarySpec) { 318 if (build32Bit) { targetPlatform arch32Name } 319 if (build64Bit) { targetPlatform arch64Name } 320 321 sources { 322 cpp { 323 source { 324 srcDirs "$jniSourceDir/main/cpp" 325 include "**/*.cc" 326 } 327 } 328 } 329 330 binaries { 331 // Build the JNI lib as a shared library. 332 withType (SharedLibraryBinarySpec) { 333 cppCompiler.define "CONSCRYPT_OPENJDK" 334 335 // Set up 32-bit vs 64-bit build 336 def building64Bit = false 337 def libPath 338 if (targetPlatform.getArchitecture().getName() == "x86") { 339 libPath = "$boringssl32BuildDir" 340 } else if (targetPlatform.getArchitecture().getName() == "x86-64") { 341 libPath = "$boringssl64BuildDir" 342 building64Bit = true 343 } else { 344 throw new GradleException("Unknown architecture: " + 345 targetPlatform.getArchitecture().name) 346 } 347 348 if (toolChain in Clang || toolChain in Gcc) { 349 cppCompiler.args "-Wall", 350 "-fPIC", 351 "-O3", 352 "-std=c++11", 353 "-I$jniSourceDir/main/include", 354 "-I$jniSourceDir/unbundled/include", 355 "-I$boringsslIncludeDir", 356 "-I$jdkIncludeDir", 357 "-I$jdkIncludeDir/linux", 358 "-I$jdkIncludeDir/darwin", 359 "-I$jdkIncludeDir/win32" 360 if (rootProject.hasProperty('checkErrorQueue')) { 361 System.out.println("Compiling with error queue checking enabled") 362 cppCompiler.define "CONSCRYPT_CHECK_ERROR_QUEUE" 363 } 364 365 // Static link to BoringSSL 366 linker.args "-O3", 367 "-fvisibility=hidden", 368 "-lstdc++", 369 libPath + "/ssl/libssl.a", 370 libPath + "/crypto/libcrypto.a" 371 } else if (toolChain in VisualCpp) { 372 cppCompiler.define "DLL_EXPORT" 373 cppCompiler.define "WIN32_LEAN_AND_MEAN" 374 cppCompiler.define "NOMINMAX" 375 if (building64Bit) { 376 cppCompiler.define "WIN64" 377 } 378 cppCompiler.define "_WINDOWS" 379 cppCompiler.define "UNICODE" 380 cppCompiler.define "_UNICODE" 381 cppCompiler.define "NDEBUG" 382 383 cppCompiler.args "/nologo", 384 "/MT", 385 "/WX-", 386 "/Wall", 387 "/O2", 388 "/Oi", 389 "/Ot", 390 "/GL", 391 "/GS", 392 "/Gy", 393 "/fp:precise", 394 "-wd4514", // Unreferenced inline function removed 395 "-wd4548", // Expression before comma has no effect 396 "-wd4625", // Copy constructor was implicitly defined as deleted 397 "-wd4626", // Assignment operator was implicitly defined as deleted 398 "-wd4710", // function not inlined 399 "-wd4711", // function inlined 400 "-wd4820", // Extra padding added to struct 401 "-wd4946", // reinterpret_cast used between related classes: 402 "-wd4996", // Thread safety for strerror 403 "-wd5027", // Move assignment operator was implicitly defined as deleted 404 "-I$jniSourceDir/main/include", 405 "-I$jniSourceDir/unbundled/include", 406 "-I$boringsslIncludeDir", 407 "-I$jdkIncludeDir", 408 "-I$jdkIncludeDir/win32" 409 410 // Static link to BoringSSL 411 linker.args "-WX", 412 "ws2_32.lib", 413 "advapi32.lib", 414 "${libPath}\\ssl\\ssl.lib", 415 "${libPath}\\crypto\\crypto.lib" 416 } 417 } 418 419 // Never build a static library. 420 withType(StaticLibraryBinarySpec) { 421 buildable = false 422 } 423 } 424 } 425 } 426 427 tasks { t -> 428 $.binaries.withType(SharedLibraryBinarySpec).each { binary -> 429 // Build the native artifact classifier from the OS and architecture. 430 def archName = binary.targetPlatform.architecture.name.replaceAll('-', '_') 431 def classifier = classifierFor(osName, archName) 432 def sourceSetName = sourceSetName("$classifier") 433 def source = binary.sharedLibraryFile 434 435 // Copies the native library to a resource location that will be included in the jar. 436 def copyTaskName = "copyNativeLib${sourceSetName}" 437 task "$copyTaskName"(type: Copy, dependsOn: binary.buildTask) { 438 from source 439 // Rename the artifact to include the generated classifier 440 rename '(.+)(\\.[^\\.]+)', "\$1-$classifier\$2" 441 // Everything under will be included in the native jar. 442 into nativeResourcesDir(classifier) + '/META-INF/native' 443 } 444 445 // Make sure we build and copy the native library to the output directory. 446 compileJava.dependsOn "$copyTaskName" 447 448 // Now define a task to strip the release binary (linux only) 449 if (osName == 'linux' && (!rootProject.hasProperty('nostrip') || 450 !rootProject.nostrip.toBoolean())) { 451 def stripTask = binary.tasks.taskName("strip") 452 task "$stripTask"(type: Exec) { 453 dependsOn binary.tasks.link 454 commandLine "strip", "${binary.tasks.link.outputFile}" 455 } 456 binary.tasks.build.dependsOn stripTask 457 } 458 } 459 } 460} 461 462boolean isExecutableOnPath(executable) { 463 FilenameFilter filter = new FilenameFilter() { 464 @Override 465 boolean accept(File dir, String name) { 466 return executable.equals(name); 467 } 468 } 469 for(String folder : System.getenv('PATH').split("" + File.pathSeparatorChar)) { 470 File[] files = file(folder).listFiles(filter) 471 if (files != null && files.size() > 0) { 472 return true; 473 } 474 } 475 return false; 476} 477 478String nativeResourcesDir(nativeClassifier) { 479 def sourceSetName = sourceSetName(nativeClassifier) 480 "${buildDir}/${sourceSetName}/resources" 481} 482 483SourceSet sourceSet(classifier) { 484 sourceSets[sourceSetName(classifier)] 485} 486 487SourceSet testSourceSet(classifier) { 488 sourceSets[testSourceSetName(classifier)] 489} 490 491static String classifierFor(osName, archName) { 492 "${osName}-${archName}" 493} 494 495static String sourceSetName(classifier) { 496 classifier.replaceAll("-", "_") 497} 498 499static String testSourceSetName(classifier) { 500 "${sourceSetName(classifier)}Test" 501} 502 503static String compileConfigurationName(classifier) { 504 sourceSetName(classifier) + "Compile" 505} 506 507