Home | History | Annotate | Download | only in openjdk
      1 description = 'Conscrypt: OpenJdk'
      2 
      3 ext {
      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 
     46 sourceSets {
     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 
     95 task platformJar(type: Jar) {
     96     from sourceSets.platform.output
     97 }
     98 
     99 if (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 
    152 configurations {
    153     publicApiDocs
    154     platform
    155 }
    156 
    157 artifacts {
    158     platform platformJar
    159 }
    160 
    161 // Append the BoringSSL-Version to the manifest.
    162 jar.manifest {
    163     attributes 'BoringSSL-Version' : boringSslVersion
    164 }
    165 
    166 dependencies {
    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 
    196 nativeClassifiers.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.
    209 def 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
    233 def 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).
    294 test.exclude("**")
    295 
    296 javadoc {
    297     options.doclet = "org.conscrypt.doclet.FilterDoclet"
    298     options.docletpath = configurations.publicApiDocs.files as List
    299 }
    300 
    301 model {
    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 
    462 boolean 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 
    478 String nativeResourcesDir(nativeClassifier) {
    479     def sourceSetName = sourceSetName(nativeClassifier)
    480     "${buildDir}/${sourceSetName}/resources"
    481 }
    482 
    483 SourceSet sourceSet(classifier) {
    484     sourceSets[sourceSetName(classifier)]
    485 }
    486 
    487 SourceSet testSourceSet(classifier) {
    488     sourceSets[testSourceSetName(classifier)]
    489 }
    490 
    491 static String classifierFor(osName, archName) {
    492     "${osName}-${archName}"
    493 }
    494 
    495 static String sourceSetName(classifier) {
    496     classifier.replaceAll("-", "_")
    497 }
    498 
    499 static String testSourceSetName(classifier) {
    500     "${sourceSetName(classifier)}Test"
    501 }
    502 
    503 static String compileConfigurationName(classifier) {
    504     sourceSetName(classifier) + "Compile"
    505 }
    506 
    507