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