Skip to content

Commit 3d914da

Browse files
committed
Move native build logic to a Kotlin class.
No functional change but removes some cruft from the openjdk build.gradle. BoringSSL build directory is still a bit of a hack but I'll address that in a later, smaller PR.
1 parent 3ec726f commit 3d914da

File tree

4 files changed

+175
-123
lines changed

4 files changed

+175
-123
lines changed

buildSrc/build.gradle.kts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
plugins {
2+
`kotlin-dsl`
3+
}
4+
5+
repositories {
6+
mavenCentral()
7+
google()
8+
}
9+
10+
dependencies {
11+
testImplementation(kotlin("test"))
12+
testImplementation(gradleTestKit())
13+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import org.gradle.api.provider.Provider
2+
import org.gradle.nativeplatform.platform.NativePlatform
3+
import java.io.File
4+
import org.gradle.api.file.Directory
5+
6+
/**
7+
* Gradle mostly uses Java os.arch names for architectures which feeds into default
8+
* targetPlatform names. Notable exception Gradle 6.9.x reports MacOS/ARM as arm-v8.
9+
*
10+
* The Maven osdetector plugin (which we recommend to developers) uses different
11+
* arch names, so that's what we need for artifacts.
12+
*
13+
* This class encapsulates both naming schemes as well as other per-platform information
14+
* about native builds, more of which will migrate in here over time.
15+
*/
16+
enum class NativeBuildVariant(
17+
val os: String,
18+
val mavenArch: String, // osdetector / Maven architecture name
19+
val gradleArch: String, // Gradle architecture, used for things like NDK or toolchain selection
20+
val boringBuildDir: String = "build64", // Where to find prebuilt libcrypto
21+
) {
22+
WINDOWS_X64("windows", "x86_64", "x86-64"),
23+
LINUX_X64("linux", "x86_64", "x86-64"),
24+
OSX_X64("osx", "x86_64", "x86-64", "build.x86"),
25+
OSX_ARM64("osx", "aarch_64", "aarch64", "build.arm");
26+
27+
override fun toString(): String
28+
= "<os=$os target=$mavenArch gradle=$gradleArch boring=$boringBuildDir>"
29+
30+
companion object {
31+
fun find(os: String, arch: String)
32+
= values().find { it.os == os && it.mavenArch == arch }
33+
fun findForGradle(os: String, arch: String)
34+
= values().find { it.os == os && it.gradleArch == arch }
35+
fun findAll(os: String) = values().filter { it.os == os }
36+
}
37+
}
38+
39+
data class NativeBuildInfo(
40+
val buildDir: Provider<Directory>,
41+
private val variant: NativeBuildVariant
42+
) {
43+
val mavenClassifier: String = "${variant.os}-${variant.mavenArch}"
44+
val targetPlatform: String = "${variant.os}_${variant.gradleArch}"
45+
46+
val nativeResourcesDir: String
47+
get() = File(buildDir.get().asFile, "$mavenClassifier/native-resources").absolutePath
48+
49+
val jarNativeResourcesDir: String
50+
get() = File(nativeResourcesDir, "META-INF/native").absolutePath
51+
52+
val boringBuildDir
53+
get() = variant.boringBuildDir
54+
55+
override fun toString(): String
56+
= "NativeBuildInfo<buildDir=${buildDir.get()} variant=$variant>"
57+
}
58+
59+
class NativeBuildResolver(private val buildDir: Provider<Directory>) {
60+
private fun wrap(variant: NativeBuildVariant?) = variant?.let {
61+
NativeBuildInfo(buildDir, it)
62+
}
63+
64+
fun find(os: String, arch: String) = wrap(NativeBuildVariant.find(os, arch))
65+
66+
fun find(nativePlatform: NativePlatform) = wrap(NativeBuildVariant.findForGradle(
67+
nativePlatform.operatingSystem.name,
68+
nativePlatform.architecture.name))
69+
70+
fun findAll(os: String): List<NativeBuildInfo> = NativeBuildVariant.findAll(os). map {
71+
NativeBuildInfo(buildDir, it)
72+
}
73+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import org.gradle.testfixtures.ProjectBuilder
2+
import kotlin.test.*
3+
4+
class NativeBuildResolverTest {
5+
@Test
6+
fun findByOsdetectorExact() {
7+
assertEquals(NativeBuildVariant.OSX_ARM64,
8+
NativeBuildVariant.find("osx", "aarch_64"))
9+
assertEquals(NativeBuildVariant.LINUX_X64,
10+
NativeBuildVariant.find("linux", "x86_64"))
11+
}
12+
13+
@Test
14+
fun findByGradleExact() {
15+
assertEquals(NativeBuildVariant.OSX_X64,
16+
NativeBuildVariant.findForGradle("osx", "x86-64"))
17+
assertEquals(NativeBuildVariant.OSX_ARM64,
18+
NativeBuildVariant.findForGradle("osx", "aarch64"))
19+
}
20+
21+
@Test
22+
fun findUnknownReturnsNull() {
23+
assertNull(NativeBuildVariant.find("linux", "armv7"))
24+
assertNull(NativeBuildVariant.findForGradle("windows", "aarch64"))
25+
}
26+
27+
@Test
28+
fun findAllByOs() {
29+
val osx = NativeBuildVariant.findAll("osx").toSet()
30+
assertEquals(setOf(NativeBuildVariant.OSX_X64, NativeBuildVariant.OSX_ARM64), osx)
31+
}
32+
33+
@Test
34+
fun computedStringsAreStable() {
35+
assertEquals("osx-aarch_64", NativeBuildVariant.OSX_ARM64.let { "${it.os}-${it.mavenArch}" })
36+
assertEquals("osx_aarch64", NativeBuildVariant.OSX_ARM64.let { "${it.os}_${it.gradleArch}" })
37+
assertEquals("build.arm", NativeBuildVariant.OSX_ARM64.boringBuildDir)
38+
assertEquals("build64", NativeBuildVariant.LINUX_X64.boringBuildDir)
39+
}
40+
41+
@Test
42+
fun directoriesAreDerivedCorrectlyFromBuilddir() {
43+
val tmp = createTempDir().apply { deleteOnExit() }
44+
val project = ProjectBuilder.builder().withProjectDir(tmp).build()
45+
val info = NativeBuildInfo(project.layout.buildDirectory, NativeBuildVariant.OSX_X64)
46+
47+
assertTrue(info.nativeResourcesDir.endsWith("osx-x86_64/native-resources"))
48+
assertTrue(info.jarNativeResourcesDir.endsWith("osx-x86_64/native-resources/META-INF/native"))
49+
assertEquals("osx-x86_64", info.mavenClassifier)
50+
assertEquals("osx_x86-64", info.targetPlatform)
51+
}
52+
53+
@Test fun resolver_wraps_variants() {
54+
val project = ProjectBuilder.builder().build()
55+
val resolver = NativeBuildResolver(project.layout.buildDirectory)
56+
57+
val info = resolver.findAll("linux").single() // Only one for now
58+
assertEquals("linux-x86_64", info.mavenClassifier)
59+
assertEquals(project.layout.buildDirectory.get().asFile, info.buildDir.get().asFile)
60+
}
61+
}

openjdk/build.gradle

Lines changed: 28 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -14,123 +14,27 @@ import org.codehaus.groovy.runtime.InvokerHelper
1414

1515
description = 'Conscrypt: OpenJdk'
1616

17-
// Gradle mostly uses Java os.arch names for architectures which feeds into default
18-
// targetPlatform names. Notable exception Gradle 6.9.x reports MacOS/ARM as
19-
// arm-v8.
20-
//
21-
// The Maven osdetector plugin (which we recommend to developers) uses different
22-
// arch names, so that's what we need for artifacts.
23-
//
24-
// This class encapsulates both naming schemes as well as other per-platform information
25-
// about native builds, more of which will migrate in here over time.
26-
enum NativeBuildInfo {
27-
WINDOWS_X86_64("windows", "x86_64"),
28-
LINUX_X86_64("linux", "x86_64"),
29-
MAC_X86_64("osx", "x86_64") {
30-
String libDir() {
31-
"build.x86"
32-
}
33-
},
34-
MAC_AARCH64("osx", "aarch_64") {
35-
String libDir() {
36-
"build.arm"
37-
}
38-
};
39-
40-
static String buildDir = "FIXME" // See below
41-
42-
public final String os
43-
public final String arch
44-
45-
// Maps osdetector arch to Gradle equivalent.
46-
private static final gradleArchMap = [
47-
"aarch_64": "aarch64",
48-
"x86_64" : "x86-64",
49-
]
50-
51-
NativeBuildInfo(String os, String arch) {
52-
this.os = os
53-
this.arch = arch
54-
}
55-
56-
// Classifier as generated by Maven osdetector.
57-
String mavenClassifier() {
58-
"${os}-${arch}"
59-
}
60-
61-
// Gradle equivalent to Maven arch
62-
String gradleArch() {
63-
gradleArch(arch)
64-
}
65-
66-
// Output directory for native resources
67-
String nativeResourcesDir() {
68-
"$buildDir/${mavenClassifier()}/native-resources"
69-
}
70-
71-
// Directory for native resources inside final jar.
72-
String jarNativeResourcesDir() {
73-
nativeResourcesDir() + '/META-INF/native'
74-
}
75-
76-
// Target platform identifier as used by Gradle
77-
String targetPlatform() {
78-
"${os}_${gradleArch()}"
79-
}
80-
81-
String libDir() {
82-
"build64"
83-
}
84-
85-
static String gradleArch(String arch) {
86-
gradleArchMap.get(arch)
87-
}
88-
89-
static NativeBuildInfo findForGradle(String os, String arch) {
90-
values().find {
91-
it.os == os && it.gradleArch() == arch
92-
}
93-
}
94-
95-
static NativeBuildInfo find(String os, String arch) {
96-
values().find {
97-
it.os == os && it.arch == arch
98-
}
99-
}
100-
101-
static NativeBuildInfo find(NativePlatform targetPlatform) {
102-
String targetOS = targetPlatform.operatingSystem.name
103-
String targetArch = targetPlatform.architecture.name
104-
def result = findForGradle(targetOS, targetArch)
105-
assert result != null : "Unknown target platform: ${targetOS}-${targetArch}"
106-
result
107-
}
108-
109-
static findAll(String os) {
110-
values().findAll {
111-
it.os == os
112-
}
113-
}
114-
}
115-
116-
// TODO: There has to be a better way of accessing Gradle properties from Groovy code than this
117-
NativeBuildInfo.buildDir = "$buildDir"
118-
11917
ext {
12018
jniSourceDir = "$rootDir/common/src/jni"
12119
assert file("$jniSourceDir").exists()
12220

12321
// Decide which targets we should build and test
124-
nativeBuilds = NativeBuildInfo.findAll("${osdetector.os}")
125-
buildToTest = NativeBuildInfo.find("${osdetector.os}", "${osdetector.arch}")
22+
nativeResolver = new NativeBuildResolver(project.layout.buildDirectory)
23+
nativeBuilds = nativeResolver.findAll("${osdetector.os}")
24+
buildToTest = nativeResolver.find("${osdetector.os}", "${osdetector.arch}")
12625

12726
assert !nativeBuilds.isEmpty() : "No native builds selected."
12827
assert buildToTest != null : "No test build selected for os.arch = ${osdetector.arch}"
12928

13029
// Compatibility with other sub-projects
131-
preferredSourceSet = buildToTest.mavenClassifier()
132-
preferredNativeFileDir = buildToTest.nativeResourcesDir()
30+
preferredSourceSet = buildToTest.mavenClassifier
31+
preferredNativeFileDir = buildToTest.nativeResourcesDir
32+
}
33+
34+
nativeBuilds.each { build ->
35+
logger.warn("Building native JNI for $build")
13336
}
37+
logger.warn("Testing against $buildToTest")
13438

13539
// Since we're not taking a direct dependency on the constants module, we need to add an
13640
// explicit task dependency to make sure the code is generated.
@@ -162,14 +66,14 @@ sourceSets {
16266
srcDirs += "${rootDir}/common/src/test/resources"
16367
// This shouldn't be needed but seems to help IntelliJ locate the native artifact.
16468
// srcDirs += preferredNativeFileDir
165-
srcDirs += buildToTest.nativeResourcesDir()
69+
srcDirs += buildToTest.nativeResourcesDir
16670
}
16771
}
16872

16973
// Add the source sets for each of the native builds
170-
nativeBuilds.each { nativeBuild ->
171-
String sourceSetName = nativeBuild.mavenClassifier()
172-
String nativeDir = nativeBuild.nativeResourcesDir()
74+
nativeBuilds.each { nativeBuildInfo ->
75+
String sourceSetName = nativeBuildInfo.mavenClassifier
76+
String nativeDir = nativeBuildInfo.nativeResourcesDir
17377

17478
// Main sources for the native build
17579
"$sourceSetName" {
@@ -293,23 +197,23 @@ dependencies {
293197
platformCompileOnly sourceSets.main.output
294198
}
295199

296-
nativeBuilds.each { nativeBuild ->
200+
nativeBuilds.each { nativeBuildInfo ->
297201
// Create the JAR task and add it's output to the published archives for this project
298-
addNativeJar(nativeBuild)
202+
addNativeJar(nativeBuildInfo)
299203

300204
// Build the classes as part of the standard build.
301-
classes.dependsOn sourceSets[nativeBuild.mavenClassifier()].classesTaskName
205+
classes.dependsOn sourceSets[nativeBuildInfo.mavenClassifier].classesTaskName
302206
}
303207

304208
// Adds a JAR task for the native library.
305-
def addNativeJar(NativeBuildInfo nativeBuild) {
209+
def addNativeJar(NativeBuildInfo nativeBuildInfo) {
306210
// Create a JAR for this configuration and add it to the output archives.
307-
SourceSet sourceSet = sourceSets[nativeBuild.mavenClassifier()]
211+
SourceSet sourceSet = sourceSets[nativeBuildInfo.mavenClassifier]
308212
def jarTask = tasks.register(sourceSet.jarTaskName, Jar) { Jar t ->
309213
// Depend on the regular classes task
310214
dependsOn classes
311215
manifest = jar.manifest
312-
archiveClassifier = nativeBuild.mavenClassifier()
216+
archiveClassifier = nativeBuildInfo.mavenClassifier
313217

314218
from sourceSet.output + sourceSets.main.output
315219

@@ -392,8 +296,8 @@ model {
392296
components {
393297
// Builds the JNI library.
394298
conscrypt_openjdk_jni(NativeLibrarySpec) {
395-
nativeBuilds.each { nativeBuild ->
396-
targetPlatform nativeBuild.targetPlatform()
299+
nativeBuilds.each { nativeBuildInfo ->
300+
targetPlatform nativeBuildInfo.targetPlatform
397301
}
398302

399303
sources {
@@ -410,8 +314,9 @@ model {
410314
withType (SharedLibraryBinarySpec) {
411315
cppCompiler.define "CONSCRYPT_OPENJDK"
412316
def jdkIncludeDir = jniIncludeDir()
413-
def nativeBuild = NativeBuildInfo.find(targetPlatform)
414-
String libPath = "$boringsslHome/${nativeBuild.libDir()}"
317+
def copy = targetPlatform
318+
def nativeBuildInfo = nativeResolver.find(targetPlatform)
319+
String libPath = boringsslHome + '/' + nativeBuildInfo.boringBuildDir
415320

416321
if (toolChain in Clang || toolChain in Gcc) {
417322
cppCompiler.args "-Wall",
@@ -503,8 +408,8 @@ model {
503408

504409
tasks { t ->
505410
$.binaries.withType(SharedLibraryBinarySpec).each { binary ->
506-
def nativeBuild = NativeBuildInfo.find(binary.targetPlatform)
507-
def classifier = nativeBuild.mavenClassifier()
411+
def nativeBuildInfo = nativeResolver.find(binary.targetPlatform)
412+
def classifier = nativeBuildInfo.mavenClassifier
508413
def source = binary.sharedLibraryFile
509414

510415
// Copies the native library to a resource location that will be included in the jar.
@@ -514,7 +419,7 @@ model {
514419
// Rename the artifact to include the generated classifier
515420
rename '(.+)(\\.[^\\.]+)', "\$1-$classifier\$2"
516421
// Everything under will be included in the native jar.
517-
into nativeBuild.jarNativeResourcesDir()
422+
into nativeBuildInfo.jarNativeResourcesDir
518423
}
519424
processResources {
520425
dependsOn copyTask

0 commit comments

Comments
 (0)