• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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