import net.corda.gradle.jarfilter.JarFilterTask import net.corda.gradle.jarfilter.MetaFixerTask import proguard.gradle.ProGuardTask import static org.gradle.api.JavaVersion.VERSION_1_8 plugins { id 'org.jetbrains.kotlin.jvm' id 'net.corda.plugins.publish-utils' id 'com.jfrog.artifactory' id 'java-library' id 'idea' } apply from: "${rootProject.projectDir}/deterministic.gradle" description 'Corda serialization (deterministic)' evaluationDependsOn(":serialization") // required by DJVM and Avian JVM (for running inside the SGX enclave) which only supports Java 8. targetCompatibility = VERSION_1_8 def javaHome = System.getProperty('java.home') def jarBaseName = "corda-${project.name}".toString() configurations { deterministicLibraries.extendsFrom implementation deterministicArtifacts.extendsFrom deterministicLibraries } dependencies { compileOnly project(':serialization') // Configure these by hand. It should be a minimal subset of dependencies, // and without any obviously non-deterministic ones such as Hibernate. // These dependencies will become "compile" scoped in our published POM. // See publish.dependenciesFrom.defaultScope. deterministicLibraries project(path: ':core-deterministic', configuration: 'deterministicArtifacts') deterministicLibraries "org.apache.qpid:proton-j:$protonj_version" // These "implementation" dependencies will become "runtime" scoped in our published POM. implementation "org.iq80.snappy:snappy:$snappy_version" implementation "com.google.guava:guava:$guava_version" } tasks.named('jar', Jar) { archiveBaseName = 'DOES-NOT-EXIST' // Don't build a jar here because it would be the wrong one. // The jar we really want will be built by the metafix task. enabled = false } def serializationJarTask = project(':serialization').tasks.named('jar', Jar) def originalJar = serializationJarTask.map { it.outputs.files.singleFile } def patchSerialization = tasks.register('patchSerialization', Zip) { dependsOn serializationJarTask destinationDirectory = file("$buildDir/source-libs") metadataCharset 'UTF-8' archiveClassifier = 'transient' archiveExtension = 'jar' from(compileKotlin) from(processResources) from(zipTree(originalJar)) { exclude 'net/corda/serialization/internal/AttachmentsClassLoaderBuilder*' exclude 'net/corda/serialization/internal/ByteBufferStreams*' exclude 'net/corda/serialization/internal/DefaultWhitelist*' exclude 'net/corda/serialization/internal/amqp/AMQPSerializerFactories*' exclude 'net/corda/serialization/internal/amqp/AMQPStreams*' exclude 'net/corda/serialization/internal/amqp/AMQPSerializationThreadContext*' exclude 'net/corda/serialization/internal/model/DefaultCacheProvider*' } reproducibleFileOrder = true includeEmptyDirs = false } def predeterminise = tasks.register('predeterminise', ProGuardTask) { dependsOn project(':core-deterministic').tasks.named('assemble') injars patchSerialization outjars file("$buildDir/proguard/pre-deterministic-${project.version}.jar") if (JavaVersion.current().isJava9Compatible()) { libraryjars "$javaHome/jmods" } else { libraryjars file("$javaHome/lib/rt.jar") libraryjars file("$javaHome/lib/jce.jar") libraryjars file("$javaHome/lib/ext/sunec.jar") } configurations.compileClasspath.forEach { if (originalJar != it) { libraryjars it, filter: '!META-INF/versions/**' } } keepattributes '*' keepdirectories dontpreverify dontobfuscate dontoptimize dontnote printseeds verbose keep '@net.corda.core.KeepForDJVM class * { *; }', includedescriptorclasses:true keepclassmembers 'class net.corda.serialization.** { public synthetic ; }' } def jarFilter = tasks.register('jarFilter', JarFilterTask) { jars predeterminise annotations { forDelete = [ "net.corda.core.DeleteForDJVM" ] forStub = [ "net.corda.core.StubOutForDJVM" ] forRemove = [ "co.paralleluniverse.fibers.Suspendable" ] forSanitise = [ "net.corda.core.DeleteForDJVM" ] } } def determinise = tasks.register('determinise', ProGuardTask) { injars jarFilter outjars file("$buildDir/proguard/$jarBaseName-${project.version}.jar") if (JavaVersion.current().isJava9Compatible()) { libraryjars "$javaHome/jmods" } else { libraryjars file("$javaHome/lib/rt.jar") libraryjars file("$javaHome/lib/jce.jar") } configurations.deterministicLibraries.forEach { libraryjars it, filter: '!META-INF/versions/**' } // Analyse the JAR for dead code, and remove (some of) it. optimizations 'code/removal/simple,code/removal/advanced' printconfiguration keepattributes '*' keepdirectories dontobfuscate dontnote printseeds verbose keep '@net.corda.core.KeepForDJVM class * { *; }', includedescriptorclasses:true keepclassmembers 'class net.corda.serialization.** { public synthetic ; }' } def checkDeterminism = tasks.register('checkDeterminism', ProGuardTask) def metafix = tasks.register('metafix', MetaFixerTask) { outputDir file("$buildDir/libs") jars determinise suffix "" // Strip timestamps from the JAR to make it reproducible. preserveTimestamps = false finalizedBy checkDeterminism } checkDeterminism.configure { dependsOn jdkTask injars metafix libraryjars deterministic_rt_jar configurations.deterministicLibraries.forEach { libraryjars it, filter: '!META-INF/versions/**' } keepattributes '*' dontpreverify dontobfuscate dontoptimize verbose keep 'class *' } defaultTasks "determinise" determinise.configure { finalizedBy metafix } tasks.named('assemble') { dependsOn checkDeterminism } def deterministicJar = metafix.map { it.outputs.files.singleFile } artifacts { deterministicArtifacts deterministicJar publish deterministicJar } tasks.named('sourceJar', Jar) { from 'README.md' include 'README.md' } tasks.named('javadocJar', Jar) { from 'README.md' include 'README.md' } publish { dependenciesFrom(configurations.deterministicArtifacts) { defaultScope = 'compile' } name jarBaseName } idea { module { if (project.hasProperty("deterministic_idea_sdk")) { jdkName project.property("deterministic_idea_sdk") as String } } }