aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-11 05:11:19 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-11 05:11:19 +0000
commit1ec8f13e5a938f306b54e76fcdf067599be5b189 (patch)
tree8bc4195c13ee1307d8932db6a918310925339f01
parent5a2654beb9ac2b94d506627057e33496b7122870 (diff)
parent446b435418361a872663352949eb46afae1ab506 (diff)
downloadndkports-android13-mainline-mediaprovider-release.tar.gz
Change-Id: I4632401a22624a84f7dd640fb3bb0bbebe4a9f6e
-rw-r--r--.gitignore15
-rw-r--r--.idea/codeStyles/Project.xml1
-rw-r--r--.idea/compiler.xml6
-rw-r--r--.idea/jarRepositories.xml35
-rw-r--r--.idea/kotlinScripting.xml5
-rw-r--r--.idea/misc.xml2
-rw-r--r--.idea/modules.xml8
-rw-r--r--.idea/ndkports.iml9
-rw-r--r--.idea/vcs.xml28
-rw-r--r--Dockerfile21
-rw-r--r--build.gradle.kts118
-rw-r--r--buildSrc/build.gradle.kts62
-rw-r--r--buildSrc/settings.gradle.kts0
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/Abi.kt (renamed from src/main/kotlin/com/android/ndkports/Result.kt)30
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/AdHocPortTask.kt77
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/AutoconfPortTask.kt (renamed from src/main/kotlin/com/android/ndkports/AutoconfPort.kt)66
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/CMakeCompatibleVersion.kt (renamed from src/main/kotlin/com/android/ndkports/CMakeCompatibleVersion.kt)4
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/CMakePortTask.kt76
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/Devices.kt89
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/MesonPortTask.kt (renamed from src/main/kotlin/com/android/ndkports/MesonPort.kt)64
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/Ndk.kt (renamed from src/main/kotlin/com/android/ndkports/Ndk.kt)2
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/NdkPortsPlugin.kt179
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/NdkVersion.kt (renamed from src/main/kotlin/com/android/ndkports/NdkVersion.kt)0
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/PackageBuilderTask.kt134
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/PortTask.kt94
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/PrefabPackageBuilder.kt183
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/PrefabSysrootPlugin.kt60
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/PrefabTask.kt95
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/SourceExtractTask.kt34
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/Testing.kt151
-rw-r--r--buildSrc/src/main/kotlin/com/android/ndkports/Toolchain.kt (renamed from src/main/kotlin/com/android/ndkports/Toolchain.kt)2
-rw-r--r--buildSrc/src/test/kotlin/com/android/ndkports/CMakeCompatibleVersionTest.kt (renamed from src/test/kotlin/com/android/ndkports/CMakeCompatibleVersionTest.kt)0
-rw-r--r--buildSrc/src/test/kotlin/com/android/ndkports/NdkVersionTest.kt (renamed from src/test/kotlin/com/android/ndkports/NdkVersionTest.kt)0
-rw-r--r--buildSrc/src/test/resources/junit-platform.properties (renamed from src/test/resources/junit-platform.properties)0
-rw-r--r--curl/build.gradle.kts106
-rw-r--r--curl/src.tar.gzbin0 -> 4144744 bytes
-rw-r--r--googletest/build.gradle.kts124
-rw-r--r--googletest/src.tar.gzbin0 -> 886330 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin56177 -> 59203 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties2
-rwxr-xr-xgradlew53
-rw-r--r--gradlew.bat43
-rw-r--r--jsoncpp/build.gradle.kts103
-rw-r--r--jsoncpp/src.tar.gzbin0 -> 216055 bytes
-rw-r--r--openssl/build.gradle.kts180
-rw-r--r--openssl/src.tar.gz (renamed from ports/openssl/src.tar.gz)bin9801502 -> 9834044 bytes
-rw-r--r--ports/curl/port.kts70
-rw-r--r--ports/curl/src.tar.gzbin4131634 -> 0 bytes
-rw-r--r--ports/jsoncpp/port.kts48
-rw-r--r--ports/jsoncpp/src.tar.gzbin200226 -> 0 bytes
-rw-r--r--ports/openssl/port.kts90
-rwxr-xr-xscripts/build.sh4
-rwxr-xr-xscripts/build_release.sh8
-rwxr-xr-xscripts/build_snapshot.sh6
-rw-r--r--settings.gradle.kts7
-rw-r--r--src/main/kotlin/com/android/ndkports/Abi.kt24
-rw-r--r--src/main/kotlin/com/android/ndkports/Cli.kt132
-rw-r--r--src/main/kotlin/com/android/ndkports/License.kt19
-rw-r--r--src/main/kotlin/com/android/ndkports/Port.kt284
-rw-r--r--src/main/kotlin/com/android/ndkports/PrefabPackageBuilder.kt253
-rw-r--r--src/main/kotlin/com/android/ndkports/Zip.kt53
-rw-r--r--src/test/kotlin/com/android/ndkports/ResultTest.kt67
62 files changed, 2038 insertions, 1288 deletions
diff --git a/.gitignore b/.gitignore
index 14e1cbc..8f8ed69 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,10 @@
.gradle
/build/
+/buildSrc/build/
+/curl/build/
+/googletest/build/
+/jsoncpp/build/
+/openssl/build/
# Ignore Gradle GUI config
gradle-app.setting
@@ -43,11 +48,11 @@ gradle-app.setting
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
-# .idea/modules.xml
-# .idea/*.iml
-# .idea/modules
-# *.iml
-# *.ipr
+.idea/modules.xml
+.idea/*.iml
+.idea/modules
+*.iml
+*.ipr
# CMake
cmake-build-*/
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index e3439a9..93ae7ac 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -10,6 +10,7 @@
</JetCodeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
+ <option name="KEEP_LINE_BREAKS" value="false" />
<option name="WRAP_ON_TYPING" value="0" />
</codeStyleSettings>
</code_scheme>
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..443b5d2
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="CompilerConfiguration">
+ <bytecodeTargetLevel target="1.6" />
+ </component>
+</project> \ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..6fde95a
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="RemoteRepositoriesConfiguration">
+ <remote-repository>
+ <option name="id" value="central" />
+ <option name="name" value="Maven Central repository" />
+ <option name="url" value="https://repo1.maven.org/maven2" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="jboss.community" />
+ <option name="name" value="JBoss Community repository" />
+ <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="MavenRepo" />
+ <option name="name" value="MavenRepo" />
+ <option name="url" value="https://repo.maven.apache.org/maven2/" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="maven" />
+ <option name="name" value="maven" />
+ <option name="url" value="https://dl.bintray.com/s1m0nw1/KtsRunner" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="BintrayJCenter" />
+ <option name="name" value="BintrayJCenter" />
+ <option name="url" value="https://jcenter.bintray.com/" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="Google" />
+ <option name="name" value="Google" />
+ <option name="url" value="https://dl.google.com/dl/android/maven2/" />
+ </remote-repository>
+ </component>
+</project> \ No newline at end of file
diff --git a/.idea/kotlinScripting.xml b/.idea/kotlinScripting.xml
index a6fe551..e56386c 100644
--- a/.idea/kotlinScripting.xml
+++ b/.idea/kotlinScripting.xml
@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinScriptingSettings">
- <option name="isAutoReloadEnabled" value="true" />
+ <scriptDefinition className="org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate" definitionName="KotlinBuildScript">
+ <order>2147483647</order>
+ <autoReloadConfigurations>true</autoReloadConfigurations>
+ </scriptDefinition>
</component>
</project> \ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index bc8d0a3..15b559a 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
- <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project> \ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 347b2d7..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
- <component name="ProjectModuleManager">
- <modules>
- <module fileurl="file://$PROJECT_DIR$/.idea/ndkports.iml" filepath="$PROJECT_DIR$/.idea/ndkports.iml" />
- </modules>
- </component>
-</project> \ No newline at end of file
diff --git a/.idea/ndkports.iml b/.idea/ndkports.iml
deleted file mode 100644
index d6ebd48..0000000
--- a/.idea/ndkports.iml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="JAVA_MODULE" version="4">
- <component name="NewModuleRootManager" inherit-compiler-output="true">
- <exclude-output />
- <content url="file://$MODULE_DIR$" />
- <orderEntry type="inheritedJdk" />
- <orderEntry type="sourceFolder" forTests="false" />
- </component>
-</module> \ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 73193ea..899b2f1 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -27,6 +27,34 @@
<option name="issueRegexp" value="\bcs/([^\s]+[\w$])" />
<option name="linkRegexp" value="https://cs.corp.google.com/search/?q=$1" />
</IssueNavigationLink>
+ <IssueNavigationLink>
+ <option name="issueRegexp" value="\bb/(\d+)(#\w+)?\b" />
+ <option name="linkRegexp" value="https://buganizer.corp.google.com/issues/$1$2" />
+ </IssueNavigationLink>
+ <IssueNavigationLink>
+ <option name="issueRegexp" value="\b(?:BUG=|FIXED=)(\d+)\b" />
+ <option name="linkRegexp" value="https://buganizer.corp.google.com/issues/$1" />
+ </IssueNavigationLink>
+ <IssueNavigationLink>
+ <option name="issueRegexp" value="\b(?:cl/|cr/|OCL=|DIFFBASE=|ROLLBACK_OF=)(\d+)\b" />
+ <option name="linkRegexp" value="https://critique.corp.google.com/$1" />
+ </IssueNavigationLink>
+ <IssueNavigationLink>
+ <option name="issueRegexp" value="\bomg/(\d+)\b" />
+ <option name="linkRegexp" value="https://omg.corp.google.com/$1" />
+ </IssueNavigationLink>
+ <IssueNavigationLink>
+ <option name="issueRegexp" value="\b(?:go/|goto/)([^,.&lt;&gt;()&quot;\s]+(?:[.,][^,.&lt;&gt;()&quot;\s]+)*)" />
+ <option name="linkRegexp" value="https://goto.google.com/$1" />
+ </IssueNavigationLink>
+ <IssueNavigationLink>
+ <option name="issueRegexp" value="\bcs/([^\s]+[\w$])" />
+ <option name="linkRegexp" value="https://cs.corp.google.com/search/?q=$1" />
+ </IssueNavigationLink>
+ <IssueNavigationLink>
+ <option name="issueRegexp" value="(LINT\.IfChange)|(LINT\.ThenChange)" />
+ <option name="linkRegexp" value="https://goto.google.com/ifthisthenthatlint" />
+ </IssueNavigationLink>
</list>
</option>
</component>
diff --git a/Dockerfile b/Dockerfile
index aba9898..ac011ef 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,15 +1,20 @@
-FROM gcr.io/cloud-builders/gradle:5.6.2-jdk-8
+FROM gcr.io/cloud-builders/javac:8
-RUN apt-get update
-RUN apt-get install -y curl
-RUN apt-get install -y ninja-build
-RUN apt-get install -y python3-pip
+RUN apt-get update && apt-get install -y \
+ cmake \
+ curl \
+ ninja-build \
+ python3-pip
RUN pip3 install meson
RUN curl -o ndk.zip \
- https://dl.google.com/android/repository/android-ndk-r20b-linux-x86_64.zip
+ https://dl.google.com/android/repository/android-ndk-r21e-linux-x86_64.zip
RUN unzip ndk.zip
-RUN mv android-ndk-r20b /ndk
+RUN mv android-ndk-r21e /ndk
+RUN curl -L -o platform-tools.zip \
+ https://dl.google.com/android/repository/platform-tools-latest-linux.zip
+RUN unzip platform-tools.zip platform-tools/adb
+RUN mv platform-tools/adb /usr/bin/adb
WORKDIR /src
ENTRYPOINT ["./gradlew"]
-CMD ["-PndkPath=/ndk", "release"]
+CMD ["--stacktrace", "-PndkPath=/ndk", "release"]
diff --git a/build.gradle.kts b/build.gradle.kts
index a00d626..f217598 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,113 +1,47 @@
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+buildscript {
+ val snapshotSuffix = if (hasProperty("release")) {
+ // We're still tagging releases as betas until we have more thorough
+ // test automation.
+ "-beta-1"
+ } else {
+ "-SNAPSHOT"
+ }
-plugins {
- kotlin("jvm") version "1.3.72"
- application
+ extra.apply {
+ set("snapshotSuffix", snapshotSuffix)
+ }
}
group = "com.android"
-version = "1.0.0-SNAPSHOT"
+version = "1.0.0${extra.get("snapshotSuffix")}"
+
+plugins {
+ distribution
+}
repositories {
mavenCentral()
jcenter()
google()
- maven(url = "https://dl.bintray.com/s1m0nw1/KtsRunner")
-}
-
-dependencies {
- implementation(kotlin("stdlib", "1.3.72"))
- implementation(kotlin("reflect", "1.3.72"))
-
- implementation("com.google.prefab:api:1.0.0")
-
- implementation("com.github.ajalt:clikt:2.2.0")
- implementation("de.swirtz:ktsRunner:0.0.7")
- implementation("org.apache.maven:maven-core:3.6.2")
- implementation("org.redundent:kotlin-xml-builder:1.5.3")
-
- testImplementation("org.jetbrains.kotlin:kotlin-test")
- testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
- testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0-M1")
- testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.0-M1")
-}
-
-application {
- // Define the main class for the application.
- mainClassName = "com.android.ndkports.CliKt"
-}
-
-tasks.withType<KotlinCompile> {
- kotlinOptions.jvmTarget = "1.8"
- kotlinOptions.freeCompilerArgs += listOf(
- "-progressive",
- "-Xuse-experimental=kotlinx.serialization.ImplicitReflectionSerializer"
- )
-}
-
-val portsBuildDir = buildDir.resolve("ports")
-
-val allPorts = listOf("openssl", "curl", "jsoncpp")
-
-// Can be specified in ~/.gradle/gradle.properties:
-//
-// ndkPath=/path/to/ndk
-//
-// Or on the command line:
-//
-// ./gradlew -PndkPath=/path/to/ndk run
-val ndkPath: String by project
-tasks.named<JavaExec>("run") {
- // Order matters since we don't do any dependency sorting, so we can't just
- // use the directory list.
- args = listOf("--ndk", ndkPath, "-o", portsBuildDir.toString()) + allPorts
-}
-
-for (port in allPorts) {
- distributions {
- create(port) {
- contents {
- includeEmptyDirs = false
- from(portsBuildDir.resolve(port)) {
- include("**/*.aar")
- include("**/*.pom")
- }
- }
- }
- }
-
- tasks.named("${port}DistTar") {
- dependsOn(":run")
- }
-
- tasks.named("${port}DistZip") {
- dependsOn(":run")
- }
}
distributions {
- create("all") {
+ main {
contents {
- includeEmptyDirs = false
- from(portsBuildDir) {
- include("**/*.aar")
- include("**/*.pom")
- }
+ from("${rootProject.buildDir}/repository")
+ include("**/*.aar")
+ include("**/*.pom")
}
}
}
-tasks.named("allDistTar") {
- dependsOn(":run")
-}
-
-tasks.named("allDistZip") {
- dependsOn(":run")
+tasks {
+ distZip {
+ dependsOn(project.getTasksByName("publish", true))
+ }
}
tasks.register("release") {
- dependsOn(":allDistZip")
- for (port in allPorts) {
- dependsOn(":${port}DistZip")
- }
+ dependsOn(project.getTasksByName("test", true))
+ dependsOn(":distZip")
}
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
new file mode 100644
index 0000000..4de21c7
--- /dev/null
+++ b/buildSrc/build.gradle.kts
@@ -0,0 +1,62 @@
+val kotlinVersion = "1.4.20"
+
+plugins {
+ id("org.jetbrains.kotlin.jvm") version "1.4.20"
+ id("java-gradle-plugin")
+ id("maven-publish")
+}
+
+group = "com.android.ndkports"
+version = "1.0.0-SNAPSHOT"
+
+repositories {
+ mavenCentral()
+ jcenter()
+ google()
+}
+
+dependencies {
+ implementation(kotlin("stdlib", kotlinVersion))
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1")
+
+ implementation("com.google.prefab:api:1.1.2")
+ implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.0")
+ implementation("org.redundent:kotlin-xml-builder:1.6.1")
+
+ testImplementation(kotlin("test", kotlinVersion))
+ testImplementation(kotlin("test-junit", kotlinVersion))
+ testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0")
+}
+
+tasks {
+ compileJava {
+ @Suppress("UnstableApiUsage")
+ options.release.set(8)
+ }
+
+ compileKotlin {
+ kotlinOptions.jvmTarget = "1.8"
+ }
+
+ compileTestKotlin {
+ kotlinOptions.jvmTarget = "1.8"
+ }
+}
+
+gradlePlugin {
+ plugins {
+ create("ndkports") {
+ id = "com.android.ndkports.NdkPorts"
+ implementationClass = "com.android.ndkports.NdkPortsPlugin"
+ }
+ }
+}
+
+publishing {
+ repositories {
+ maven {
+ url = uri("${rootProject.buildDir}/repository")
+ }
+ }
+}
diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/buildSrc/settings.gradle.kts
diff --git a/src/main/kotlin/com/android/ndkports/Result.kt b/buildSrc/src/main/kotlin/com/android/ndkports/Abi.kt
index 21c203e..155c59c 100644
--- a/src/main/kotlin/com/android/ndkports/Result.kt
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/Abi.kt
@@ -16,21 +16,23 @@
package com.android.ndkports
-sealed class Result<out T, out E> {
- data class Ok<T>(val value: T) : Result<T, Nothing>()
- data class Error<E>(val error: E) : Result<Nothing, E>()
+import java.util.Collections.max
- inline fun onSuccess(block: (T) -> Unit): Result<T, E> {
- if (this is Ok<T>) {
- block(value)
- }
- return this
- }
+enum class Abi(
+ val archName: String,
+ val abiName: String,
+ val triple: String,
+ val minSupportedVersion: Int
+) {
+ Arm("arm", "armeabi-v7a", "arm-linux-androideabi", 16),
+ Arm64("arm64", "arm64-v8a", "aarch64-linux-android", 21),
+ X86("x86", "x86", "i686-linux-android", 16),
+ X86_64("x86_64", "x86_64", "x86_64-linux-android", 21);
+
+ fun adjustMinSdkVersion(minSdkVersion: Int) =
+ max(listOf(minSdkVersion, minSupportedVersion))
- inline fun onFailure(block: (E) -> Unit): Result<T, E> {
- if (this is Error<E>) {
- block(error)
- }
- return this
+ companion object {
+ fun fromAbiName(name: String) = values().find { it.abiName == name }
}
} \ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/com/android/ndkports/AdHocPortTask.kt b/buildSrc/src/main/kotlin/com/android/ndkports/AdHocPortTask.kt
new file mode 100644
index 0000000..4c9fcbc
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/AdHocPortTask.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ndkports
+
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.Input
+import java.io.File
+
+open class RunBuilder {
+ val cmd = mutableListOf<String>()
+ fun arg(arg: String) = cmd.add(arg)
+ fun args(vararg args: String) = cmd.addAll(args)
+
+ val env = mutableMapOf<String, String>()
+ fun env(key: String, value: String) = env.set(key, value)
+}
+
+class AdHocBuilder(
+ val sourceDirectory: File,
+ val buildDirectory: File,
+ val installDirectory: File,
+ val toolchain: Toolchain,
+ val sysroot: File,
+ val ncpus: Int,
+) {
+ val runs = mutableListOf<RunBuilder>()
+ fun run(block: RunBuilder.() -> Unit) {
+ runs.add(RunBuilder().apply { block() })
+ }
+}
+
+abstract class AdHocPortTask : PortTask() {
+ @get:Input
+ abstract val builder: Property<AdHocBuilder.() -> Unit>
+
+ fun builder(block: AdHocBuilder.() -> Unit) = builder.set(block)
+
+ override fun buildForAbi(
+ toolchain: Toolchain,
+ workingDirectory: File,
+ buildDirectory: File,
+ installDirectory: File
+ ) {
+ buildDirectory.mkdirs()
+
+ val builderBlock = builder.get()
+ val builder = AdHocBuilder(
+ sourceDirectory.get().asFile,
+ buildDirectory,
+ installDirectory,
+ toolchain,
+ prefabGenerated.get().asFile,
+ ncpus,
+ )
+ builder.builderBlock()
+
+ for (run in builder.runs) {
+ executeSubprocess(
+ run.cmd, buildDirectory, additionalEnvironment = run.env
+ )
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/kotlin/com/android/ndkports/AutoconfPort.kt b/buildSrc/src/main/kotlin/com/android/ndkports/AutoconfPortTask.kt
index 1c009cb..e288e33 100644
--- a/src/main/kotlin/com/android/ndkports/AutoconfPort.kt
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/AutoconfPortTask.kt
@@ -16,33 +16,39 @@
package com.android.ndkports
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.Input
import java.io.File
-abstract class AutoconfPort : Port() {
- open fun configureArgs(
- workingDirectory: File,
- toolchain: Toolchain
- ): List<String> = emptyList()
+class AutoconfBuilder(val toolchain: Toolchain, val sysroot: File) :
+ RunBuilder()
- open fun configureEnv(
- workingDirectory: File,
- toolchain: Toolchain
- ): Map<String, String> = emptyMap()
+abstract class AutoconfPortTask : PortTask() {
+ @get:Input
+ abstract val autoconf: Property<AutoconfBuilder.() -> Unit>
- override fun configure(
+ fun autoconf(block: AutoconfBuilder.() -> Unit) = autoconf.set(block)
+
+ override fun buildForAbi(
toolchain: Toolchain,
- sourceDirectory: File,
+ workingDirectory: File,
buildDirectory: File,
- installDirectory: File,
- workingDirectory: File
- ): Result<Unit, String> {
+ installDirectory: File
+ ) {
buildDirectory.mkdirs()
- return executeProcessStep(
- listOf(
- "${sourceDirectory.absolutePath}/configure",
- "--host=${toolchain.binutilsTriple}",
- "--prefix=${installDirectory.absolutePath}"
- ) + configureArgs(workingDirectory, toolchain),
+
+ val autoconfBlock = autoconf.get()
+ val builder = AutoconfBuilder(
+ toolchain,
+ prefabGenerated.get().asFile.resolve(toolchain.abi.triple)
+ )
+ builder.autoconfBlock()
+
+ executeSubprocess(listOf(
+ "${sourceDirectory.get().asFile.absolutePath}/configure",
+ "--host=${toolchain.binutilsTriple}",
+ "--prefix=${installDirectory.absolutePath}"
+ ) + builder.cmd,
buildDirectory,
additionalEnvironment = mutableMapOf(
"AR" to toolchain.ar.absolutePath,
@@ -51,24 +57,12 @@ abstract class AutoconfPort : Port() {
"RANLIB" to toolchain.ranlib.absolutePath,
"STRIP" to toolchain.strip.absolutePath,
"PATH" to "${toolchain.binDir}:${System.getenv("PATH")}"
- ).apply { putAll(configureEnv(workingDirectory, toolchain)) }
- )
- }
+ ).apply { putAll(builder.env) })
- override fun build(
- toolchain: Toolchain,
- buildDirectory: File
- ): Result<Unit, String> =
- executeProcessStep(
- listOf("make", "-j$ncpus"), buildDirectory
- )
+ executeSubprocess(listOf("make", "-j$ncpus"), buildDirectory)
- override fun install(
- toolchain: Toolchain,
- buildDirectory: File,
- installDirectory: File
- ): Result<Unit, String> =
- executeProcessStep(
+ executeSubprocess(
listOf("make", "-j$ncpus", "install"), buildDirectory
)
+ }
} \ No newline at end of file
diff --git a/src/main/kotlin/com/android/ndkports/CMakeCompatibleVersion.kt b/buildSrc/src/main/kotlin/com/android/ndkports/CMakeCompatibleVersion.kt
index 6d3ee45..ba58ccb 100644
--- a/src/main/kotlin/com/android/ndkports/CMakeCompatibleVersion.kt
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/CMakeCompatibleVersion.kt
@@ -16,7 +16,7 @@
package com.android.ndkports
-import java.io.File
+import java.io.Serializable
/**
* A version number that is compatible with CMake's package version format.
@@ -31,7 +31,7 @@ data class CMakeCompatibleVersion(
val minor: Int?,
val patch: Int?,
val tweak: Int?
-) {
+) : Serializable {
init {
if (tweak != null) {
require(patch != null)
diff --git a/buildSrc/src/main/kotlin/com/android/ndkports/CMakePortTask.kt b/buildSrc/src/main/kotlin/com/android/ndkports/CMakePortTask.kt
new file mode 100644
index 0000000..dba2017
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/CMakePortTask.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ndkports
+
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.Input
+import java.io.File
+
+class CMakeBuilder(val toolchain: Toolchain, val sysroot: File) :
+ RunBuilder()
+
+abstract class CMakePortTask : PortTask() {
+ @get:Input
+ abstract val cmake: Property<CMakeBuilder.() -> Unit>
+
+ fun cmake(block: CMakeBuilder.() -> Unit) = cmake.set(block)
+
+ override fun buildForAbi(
+ toolchain: Toolchain,
+ workingDirectory: File,
+ buildDirectory: File,
+ installDirectory: File
+ ) {
+ configure(toolchain, buildDirectory, installDirectory)
+ build(buildDirectory)
+ install(buildDirectory)
+ }
+
+ private fun configure(
+ toolchain: Toolchain, buildDirectory: File, installDirectory: File
+ ) {
+ val cmakeBlock = cmake.get()
+ val builder = CMakeBuilder(
+ toolchain,
+ prefabGenerated.get().asFile.resolve(toolchain.abi.triple)
+ )
+ builder.cmakeBlock()
+
+ val toolchainFile =
+ toolchain.ndk.path.resolve("build/cmake/android.toolchain.cmake")
+
+ buildDirectory.mkdirs()
+ executeSubprocess(
+ listOf(
+ "cmake",
+ "-DCMAKE_TOOLCHAIN_FILE=${toolchainFile.absolutePath}",
+ "-DCMAKE_BUILD_TYPE=RelWithDebInfo",
+ "-DCMAKE_INSTALL_PREFIX=${installDirectory.absolutePath}",
+ "-DANDROID_ABI=${toolchain.abi.abiName}",
+ "-DANDROID_API_LEVEL=${toolchain.api}",
+ "-GNinja",
+ sourceDirectory.get().asFile.absolutePath,
+ ) + builder.cmd, buildDirectory, builder.env
+ )
+ }
+
+ private fun build(buildDirectory: File) =
+ executeSubprocess(listOf("ninja", "-v"), buildDirectory)
+
+ private fun install(buildDirectory: File) =
+ executeSubprocess(listOf("ninja", "-v", "install"), buildDirectory)
+} \ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/com/android/ndkports/Devices.kt b/buildSrc/src/main/kotlin/com/android/ndkports/Devices.kt
new file mode 100644
index 0000000..3ed1d9a
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/Devices.kt
@@ -0,0 +1,89 @@
+package com.android.ndkports
+
+import java.io.File
+
+data class AdbException(val args: Iterable<String>, val output: String) :
+ RuntimeException("${formatCmd(args)}:\n$output") {
+ val cmd: String by lazy { formatCmd(args) }
+
+ companion object {
+ fun formatCmd(args: Iterable<String>) = args.joinToString(" ")
+ }
+}
+
+private fun adb(args: Iterable<String>, serial: String? = null): String {
+ val adbCmd = if (serial == null) {
+ listOf("adb")
+ } else {
+ listOf("adb", "-s", serial)
+ }
+ val result = ProcessBuilder(adbCmd + args).redirectErrorStream(true).start()
+ val output = result.inputStream.bufferedReader().use { it.readText() }
+ if (result.waitFor() != 0) {
+ throw AdbException(args, output)
+ }
+ return output
+}
+
+data class Device(val serial: String) {
+ private val abis: List<Abi> by lazy {
+ val abiProps = listOf(
+ "ro.product.cpu.abi",
+ "ro.product.cpu.abi2",
+ "ro.product.cpu.abilist",
+ )
+ val abiSet = mutableSetOf<Abi>()
+ for (abiProp in abiProps) {
+ for (abiName in getProp(abiProp).trim().split(",")) {
+ Abi.fromAbiName(abiName)?.let { abiSet.add(it) }
+ }
+ }
+ abiSet.toList().sortedBy { it.abiName }
+ }
+
+ private val version: Int by lazy {
+ getProp("ro.build.version.sdk").trim().toInt()
+ }
+
+ fun compatibleWith(abi: Abi, minSdkVersion: Int) =
+ abi in abis && minSdkVersion <= version
+
+ fun push(src: File, dest: File) =
+ run(listOf("push", src.toString(), dest.toString()))
+
+ fun shell(cmd: Iterable<String>) = run(listOf("shell") + cmd)
+
+ private fun getProp(name: String): String = shell(listOf("getprop", name))
+
+ private fun run(args: Iterable<String>): String = adb(args, serial)
+}
+
+class DeviceFleet {
+ private fun lineHasUsableDevice(line: String): Boolean {
+ if (line.isBlank()) {
+ return false
+ }
+ if (line == "List of devices attached") {
+ return false
+ }
+ if (line.contains("offline")) {
+ return false
+ }
+ if (line.contains("unauthorized")) {
+ return false
+ }
+ if (line.startsWith("* daemon")) {
+ return false
+ }
+ return true
+ }
+
+ private val devices: List<Device> by lazy {
+ adb(listOf("devices")).lines().filter { lineHasUsableDevice(it) }.map {
+ Device(it.split("\\s".toRegex()).first())
+ }
+ }
+
+ fun findDeviceFor(abi: Abi, minSdkVersion: Int): Device? =
+ devices.find { it.compatibleWith(abi, minSdkVersion) }
+} \ No newline at end of file
diff --git a/src/main/kotlin/com/android/ndkports/MesonPort.kt b/buildSrc/src/main/kotlin/com/android/ndkports/MesonPortTask.kt
index 8c1f706..6be9b9e 100644
--- a/src/main/kotlin/com/android/ndkports/MesonPort.kt
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/MesonPortTask.kt
@@ -16,24 +16,41 @@
package com.android.ndkports
+import org.gradle.api.model.ObjectFactory
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.Input
import java.io.File
+import javax.inject.Inject
-abstract class MesonPort : Port() {
+@Suppress("UnstableApiUsage")
+abstract class MesonPortTask @Inject constructor(objects: ObjectFactory) :
+ PortTask() {
enum class DefaultLibraryType(val argument: String) {
- Both("both"),
- Shared("shared"),
- Static("static")
+ Both("both"), Shared("shared"), Static("static")
}
- open val defaultLibraryType: DefaultLibraryType = DefaultLibraryType.Shared
+ @get:Input
+ val defaultLibraryType: Property<DefaultLibraryType> =
+ objects.property(DefaultLibraryType::class.java)
+ .convention(DefaultLibraryType.Shared)
- override fun configure(
+ override fun buildForAbi(
toolchain: Toolchain,
- sourceDirectory: File,
+ workingDirectory: File,
buildDirectory: File,
- installDirectory: File,
- workingDirectory: File
- ): Result<Unit, String> {
+ installDirectory: File
+ ) {
+ configure(toolchain, workingDirectory, buildDirectory, installDirectory)
+ build(buildDirectory)
+ install(buildDirectory)
+ }
+
+ private fun configure(
+ toolchain: Toolchain,
+ workingDirectory: File,
+ buildDirectory: File,
+ installDirectory: File
+ ) {
val cpuFamily = when (toolchain.abi) {
Abi.Arm -> "arm"
Abi.Arm64 -> "aarch64"
@@ -49,7 +66,8 @@ abstract class MesonPort : Port() {
}
val crossFile = workingDirectory.resolve("cross_file.txt").apply {
- writeText("""
+ writeText(
+ """
[binaries]
ar = '${toolchain.ar}'
c = '${toolchain.clang}'
@@ -61,10 +79,11 @@ abstract class MesonPort : Port() {
cpu_family = '$cpuFamily'
cpu = '$cpu'
endian = 'little'
- """.trimIndent())
+ """.trimIndent()
+ )
}
- return executeProcessStep(
+ executeSubprocess(
listOf(
"meson",
"--cross-file",
@@ -74,23 +93,16 @@ abstract class MesonPort : Port() {
"--prefix",
installDirectory.absolutePath,
"--default-library",
- defaultLibraryType.argument,
- sourceDirectory.absolutePath,
+ defaultLibraryType.get().argument,
+ sourceDirectory.get().asFile.absolutePath,
buildDirectory.absolutePath
), workingDirectory
)
}
- override fun build(
- toolchain: Toolchain,
- buildDirectory: File
- ): Result<Unit, String> =
- executeProcessStep(listOf("ninja", "-v"), buildDirectory)
+ private fun build(buildDirectory: File) =
+ executeSubprocess(listOf("ninja", "-v"), buildDirectory)
- override fun install(
- toolchain: Toolchain,
- buildDirectory: File,
- installDirectory: File
- ): Result<Unit, String> =
- executeProcessStep(listOf("ninja", "-v", "install"), buildDirectory)
+ private fun install(buildDirectory: File) =
+ executeSubprocess(listOf("ninja", "-v", "install"), buildDirectory)
} \ No newline at end of file
diff --git a/src/main/kotlin/com/android/ndkports/Ndk.kt b/buildSrc/src/main/kotlin/com/android/ndkports/Ndk.kt
index af66cb5..7ccd255 100644
--- a/src/main/kotlin/com/android/ndkports/Ndk.kt
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/Ndk.kt
@@ -17,7 +17,6 @@
package com.android.ndkports
import java.io.File
-import java.lang.RuntimeException
class Ndk(val path: File) {
val version = NdkVersion.fromNdk(path)
@@ -36,4 +35,5 @@ class Ndk(val path: File) {
private val toolchainDirectory = llvmBaseDir.resolve(hostTag)
val toolchainBinDirectory = toolchainDirectory.resolve("bin")
+ val sysrootDirectory = toolchainDirectory.resolve("sysroot")
} \ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/com/android/ndkports/NdkPortsPlugin.kt b/buildSrc/src/main/kotlin/com/android/ndkports/NdkPortsPlugin.kt
new file mode 100644
index 0000000..ff629c0
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/NdkPortsPlugin.kt
@@ -0,0 +1,179 @@
+package com.android.ndkports
+
+import org.gradle.api.InvalidUserDataException
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.attributes.Attribute
+import org.gradle.api.component.SoftwareComponentFactory
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.file.RegularFileProperty
+import org.gradle.api.model.ObjectFactory
+import org.gradle.api.plugins.BasePlugin
+import org.gradle.api.provider.Property
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.bundling.Zip
+import javax.inject.Inject
+
+abstract class NdkPortsExtension {
+ abstract val source: RegularFileProperty
+
+ abstract val ndkPath: DirectoryProperty
+
+ abstract val minSdkVersion: Property<Int>
+}
+
+class NdkPortsPluginImpl(
+ private val project: Project,
+ private val softwareComponentFactory: SoftwareComponentFactory,
+ objects: ObjectFactory,
+) {
+ private val topBuildDir = project.buildDir.resolve("port")
+
+ private val extension =
+ project.extensions.create("ndkPorts", NdkPortsExtension::class.java)
+
+ private var portTaskAdded: Boolean = false
+ private val portTask = objects.property(PortTask::class.java)
+ private lateinit var prefabTask: Provider<PrefabTask>
+ private lateinit var extractTask: Provider<SourceExtractTask>
+ private lateinit var packageTask: Provider<PackageBuilderTask>
+ private lateinit var aarTask: Provider<Zip>
+
+ private lateinit var implementation: Configuration
+ private lateinit var exportedAars: Configuration
+ private lateinit var consumedAars: Configuration
+
+ private val artifactType = Attribute.of("artifactType", String::class.java)
+
+ private fun createConfigurations() {
+ implementation = project.configurations.create("implementation") {
+ it.isCanBeResolved = false
+ it.isCanBeConsumed = false
+ }
+
+ exportedAars = project.configurations.create("exportedAars") {
+ it.isCanBeResolved = false
+ it.isCanBeConsumed = true
+ it.extendsFrom(implementation)
+ it.attributes { attributes ->
+ with(attributes) {
+ attribute(artifactType, "aar")
+ }
+ }
+ }
+
+ consumedAars = project.configurations.create("consumedAars") {
+ it.isCanBeResolved = true
+ it.isCanBeConsumed = false
+ it.extendsFrom(implementation)
+ it.attributes { attributes ->
+ with(attributes) {
+ attribute(artifactType, "aar")
+ }
+ }
+ }
+ }
+
+ private fun createTasks() {
+ prefabTask = project.tasks.register("prefab", PrefabTask::class.java) {
+ with(it) {
+ aars = consumedAars.incoming.artifacts.artifactFiles
+ outputDirectory.set(topBuildDir.resolve("dependencies"))
+ ndkPath.set(extension.ndkPath)
+ minSdkVersion.set(extension.minSdkVersion)
+ }
+ }
+
+ extractTask = project.tasks.register(
+ "extractSrc", SourceExtractTask::class.java
+ ) {
+ with(it) {
+ source.set(extension.source)
+ outDir.set(topBuildDir.resolve("src"))
+ }
+ }
+
+ packageTask = project.tasks.register(
+ "prefabPackage", PackageBuilderTask::class.java
+ ) {
+ if (!portTask.isPresent) {
+ throw InvalidUserDataException(
+ "The ndkports plugin was applied but no port task was " +
+ "registered. A task deriving from NdkPortsTask " +
+ "must be registered."
+ )
+ }
+ with(it) {
+ sourceDirectory.set(extractTask.get().outDir)
+ outDir.set(topBuildDir)
+ ndkPath.set(extension.ndkPath)
+ installDirectory.set(portTask.get().installDir)
+ minSdkVersion.set(extension.minSdkVersion)
+ }
+ }
+
+ aarTask = project.tasks.register("packageAar", Zip::class.java) {
+ it.from(packageTask.get().intermediatesDirectory)
+ it.archiveExtension.set("aar")
+ it.dependsOn(packageTask)
+ }
+
+ project.artifacts.add(exportedAars.name, aarTask)
+
+ val portTasks = project.tasks.withType(PortTask::class.java)
+ portTasks.whenTaskAdded { portTask ->
+ if (portTaskAdded) {
+ throw InvalidUserDataException(
+ "Cannot define multiple port tasks for a single module"
+ )
+ }
+ portTaskAdded = true
+ this.portTask.set(portTask)
+
+ with (portTask) {
+ sourceDirectory.set(extractTask.get().outDir)
+ ndkPath.set(extension.ndkPath)
+ buildDir.set(topBuildDir)
+ minSdkVersion.set(extension.minSdkVersion)
+ prefabGenerated.set(prefabTask.get().generatedDirectory)
+ }
+ }
+
+ val testTasks =
+ project.tasks.withType(AndroidExecutableTestTask::class.java)
+ testTasks.whenTaskAdded { testTask ->
+ with (testTask) {
+ dependsOn(aarTask)
+ minSdkVersion.set(extension.minSdkVersion)
+ ndkPath.set(extension.ndkPath)
+ }
+ project.tasks.getByName("check").dependsOn(testTask)
+ }
+ }
+
+ private fun createComponents() {
+ val adhocComponent = softwareComponentFactory.adhoc("prefab")
+ project.components.add(adhocComponent)
+ adhocComponent.addVariantsFromConfiguration(exportedAars) {
+ it.mapToMavenScope("runtime")
+ }
+ }
+
+ fun apply() {
+ project.pluginManager.apply(BasePlugin::class.java)
+ createConfigurations()
+ createTasks()
+ createComponents()
+ }
+}
+
+@Suppress("UnstableApiUsage", "Unused")
+class NdkPortsPlugin @Inject constructor(
+ private val objects: ObjectFactory,
+ private val softwareComponentFactory: SoftwareComponentFactory,
+) : Plugin<Project> {
+ override fun apply(project: Project) {
+ NdkPortsPluginImpl(project, softwareComponentFactory, objects).apply()
+ }
+} \ No newline at end of file
diff --git a/src/main/kotlin/com/android/ndkports/NdkVersion.kt b/buildSrc/src/main/kotlin/com/android/ndkports/NdkVersion.kt
index fce1304..fce1304 100644
--- a/src/main/kotlin/com/android/ndkports/NdkVersion.kt
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/NdkVersion.kt
diff --git a/buildSrc/src/main/kotlin/com/android/ndkports/PackageBuilderTask.kt b/buildSrc/src/main/kotlin/com/android/ndkports/PackageBuilderTask.kt
new file mode 100644
index 0000000..a7c408d
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/PackageBuilderTask.kt
@@ -0,0 +1,134 @@
+package com.android.ndkports
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.NamedDomainObjectContainer
+import org.gradle.api.Project
+import org.gradle.api.file.Directory
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.model.ObjectFactory
+import org.gradle.api.provider.ListProperty
+import org.gradle.api.provider.MapProperty
+import org.gradle.api.provider.Property
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputDirectory
+import org.gradle.api.tasks.Internal
+import org.gradle.api.tasks.Nested
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.TaskAction
+import javax.inject.Inject
+
+abstract class ModuleProperty @Inject constructor(
+ objectFactory: ObjectFactory,
+ @get:Input val name: String,
+) {
+ @Suppress("UnstableApiUsage")
+ @get:Input
+ val static: Property<Boolean> =
+ objectFactory.property(Boolean::class.java).convention(false)
+
+ @Suppress("UnstableApiUsage")
+ @get:Input
+ val headerOnly: Property<Boolean> =
+ objectFactory.property(Boolean::class.java).convention(false)
+
+ @Suppress("UnstableApiUsage")
+ @get:Input
+ val includesPerAbi: Property<Boolean> =
+ objectFactory.property(Boolean::class.java).convention(false)
+
+ @Suppress("UnstableApiUsage")
+ @get:Input
+ val dependencies: ListProperty<String> =
+ objectFactory.listProperty(String::class.java).convention(emptyList())
+}
+
+abstract class PackageBuilderTask @Inject constructor(
+ objectFactory: ObjectFactory,
+) : DefaultTask() {
+ /**
+ * The name of the port. Will be used as the package name in prefab.json.
+ */
+ @Suppress("UnstableApiUsage")
+ @get:Input
+ val packageName: Property<String> =
+ objectFactory.property(String::class.java).convention(project.name)
+
+ /**
+ * The version to encode in the prefab.json.
+ *
+ * This version must be compatible with CMake's `find_package` for
+ * config-style packages. This means that it must be one to four decimal
+ * separated integers. No other format is allowed.
+ *
+ * If not set, the default is [Project.getVersion] as interpreted by
+ * [CMakeCompatibleVersion.parse].
+ *
+ * For example, OpenSSL 1.1.1g will set this value to
+ * `CMakeCompatibleVersion(1, 1, 1, 7)`.
+ */
+ @get:Input
+ abstract val version: Property<CMakeCompatibleVersion>
+
+ @get:Input
+ abstract val minSdkVersion: Property<Int>
+
+ @get:Nested
+ abstract val modules: NamedDomainObjectContainer<ModuleProperty>
+
+ @Suppress("UnstableApiUsage")
+ @get:Input
+ val licensePath: Property<String> =
+ objectFactory.property(String::class.java).convention("LICENSE")
+
+ @Suppress("UnstableApiUsage")
+ @get:Input
+ abstract val dependencies: MapProperty<String, String>
+
+ @get:InputDirectory
+ abstract val sourceDirectory: DirectoryProperty
+
+ @get:InputDirectory
+ abstract val installDirectory: DirectoryProperty
+
+ @get:Internal
+ abstract val outDir: DirectoryProperty
+
+ @get:OutputDirectory
+ val intermediatesDirectory: Provider<Directory>
+ get() = outDir.dir("aar")
+
+ @get:InputDirectory
+ abstract val ndkPath: DirectoryProperty
+
+ private val ndk: Ndk
+ get() = Ndk(ndkPath.asFile.get())
+
+ @TaskAction
+ fun run() {
+ val modules = modules.asMap.values.map {
+ ModuleDescription(
+ it.name,
+ it.static.get(),
+ it.headerOnly.get(),
+ it.includesPerAbi.get(),
+ it.dependencies.get()
+ )
+ }
+ PrefabPackageBuilder(
+ PackageData(
+ packageName.get(),
+ project.version as String,
+ version.get(),
+ minSdkVersion.get(),
+ licensePath.get(),
+ modules,
+ dependencies.get(),
+ ),
+ intermediatesDirectory.get().asFile,
+ installDirectory.get().asFile,
+ sourceDirectory.get().asFile,
+ ndk,
+ ).build()
+ }
+} \ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/com/android/ndkports/PortTask.kt b/buildSrc/src/main/kotlin/com/android/ndkports/PortTask.kt
new file mode 100644
index 0000000..223afb0
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/PortTask.kt
@@ -0,0 +1,94 @@
+package com.android.ndkports
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.Directory
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.provider.Property
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputDirectory
+import org.gradle.api.tasks.Internal
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.TaskAction
+import java.io.File
+
+@Suppress("UnstableApiUsage")
+abstract class PortTask : DefaultTask() {
+
+ @get:InputDirectory
+ abstract val sourceDirectory: DirectoryProperty
+
+ @get:OutputDirectory
+ abstract val buildDir: DirectoryProperty
+
+ @get:OutputDirectory
+ val installDir: Provider<Directory>
+ get() = buildDir.dir("install")
+
+ @get:InputDirectory
+ abstract val prefabGenerated: DirectoryProperty
+
+ @get:Input
+ abstract val minSdkVersion: Property<Int>
+
+ @get:InputDirectory
+ abstract val ndkPath: DirectoryProperty
+
+ private val ndk: Ndk
+ get() = Ndk(ndkPath.asFile.get())
+
+ /**
+ * The number of CPUs available for building.
+ *
+ * May be passed to the build system if required.
+ */
+ @Internal
+ protected val ncpus = Runtime.getRuntime().availableProcessors()
+
+ protected fun executeSubprocess(
+ args: List<String>,
+ workingDirectory: File,
+ additionalEnvironment: Map<String, String>? = null
+ ) {
+ val pb = ProcessBuilder(args).redirectErrorStream(true)
+ .directory(workingDirectory)
+
+ if (additionalEnvironment != null) {
+ pb.environment().putAll(additionalEnvironment)
+ }
+
+ val result = pb.start()
+ val output = result.inputStream.bufferedReader().use { it.readText() }
+ if (result.waitFor() != 0) {
+ throw RuntimeException("Subprocess failed with:\n$output")
+ }
+ }
+
+ @Suppress("MemberVisibilityCanBePrivate")
+ fun buildDirectoryFor(abi: Abi): File =
+ buildDir.asFile.get().resolve("build/$abi")
+
+ @Suppress("MemberVisibilityCanBePrivate")
+ fun installDirectoryFor(abi: Abi): File =
+ installDir.get().asFile.resolve("$abi")
+
+ @TaskAction
+ fun run() {
+ for (abi in Abi.values()) {
+ val api = abi.adjustMinSdkVersion(minSdkVersion.get())
+ buildForAbi(
+ Toolchain(ndk, abi, api),
+ buildDir.asFile.get(),
+ buildDirectory = buildDirectoryFor(abi),
+ installDirectory = installDirectoryFor(abi),
+ )
+ }
+ }
+
+ abstract fun buildForAbi(
+ toolchain: Toolchain,
+ workingDirectory: File,
+ buildDirectory: File,
+ installDirectory: File
+ )
+} \ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/com/android/ndkports/PrefabPackageBuilder.kt b/buildSrc/src/main/kotlin/com/android/ndkports/PrefabPackageBuilder.kt
new file mode 100644
index 0000000..27be792
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/PrefabPackageBuilder.kt
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ndkports
+
+import com.google.prefab.api.AndroidAbiMetadata
+import com.google.prefab.api.ModuleMetadataV1
+import com.google.prefab.api.PackageMetadataV1
+import kotlinx.serialization.encodeToString
+import kotlinx.serialization.json.Json
+import org.redundent.kotlin.xml.xml
+import java.io.File
+import java.io.Serializable
+
+data class PackageData(
+ val name: String,
+ val mavenVersion: String,
+ val prefabVersion: CMakeCompatibleVersion,
+ val minSdkVersion: Int,
+ val licensePath: String,
+ val modules: List<ModuleDescription>,
+ val dependencies: Map<String, String>,
+)
+
+/**
+ * A module exported by the package.
+ *
+ * As currently implemented by ndkports, one module is exactly one library.
+ * Prefab supports header-only libraries, but ndkports does not support these
+ * yet.
+ *
+ * Static libraries are not currently supported by ndkports.
+ *
+ * @property[name] The name of the module. Note that currently the name of the
+ * installed library file must be exactly `lib$name.so`.
+ * @property[includesPerAbi] Set to true if a different set of headers should be
+ * exposed per-ABI. Not currently implemented.
+ * @property[dependencies] A list of other modules required by this module, in
+ * the format described by https://google.github.io/prefab/.
+ */
+data class ModuleDescription(
+ val name: String,
+ val static: Boolean,
+ val headerOnly: Boolean,
+ val includesPerAbi: Boolean,
+ val dependencies: List<String>,
+) : Serializable
+
+class PrefabPackageBuilder(
+ private val packageData: PackageData,
+ private val packageDirectory: File,
+ private val directory: File,
+ private val sourceDirectory: File,
+ private val ndk: Ndk,
+) {
+ private val prefabDirectory = packageDirectory.resolve("prefab")
+ private val modulesDirectory = prefabDirectory.resolve("modules")
+
+ // TODO: Get from gradle.
+ private val packageName = "com.android.ndk.thirdparty.${packageData.name}"
+
+ private fun preparePackageDirectory() {
+ if (packageDirectory.exists()) {
+ packageDirectory.deleteRecursively()
+ }
+ modulesDirectory.mkdirs()
+ }
+
+ private fun makePackageMetadata() {
+ prefabDirectory.resolve("prefab.json").writeText(
+ Json.encodeToString(
+ PackageMetadataV1(
+ packageData.name,
+ schemaVersion = 1,
+ dependencies = packageData.dependencies.keys.toList(),
+ version = packageData.prefabVersion.toString()
+ )
+ )
+ )
+ }
+
+ private fun makeModuleMetadata(module: ModuleDescription, moduleDirectory: File) {
+ moduleDirectory.resolve("module.json").writeText(
+ Json.encodeToString(
+ ModuleMetadataV1(
+ exportLibraries = module.dependencies
+ )
+ )
+ )
+ }
+
+ private fun installLibForAbi(module: ModuleDescription, abi: Abi, libsDir: File) {
+ val extension = if (module.static) "a" else "so"
+ val libName = "lib${module.name}.${extension}"
+ val installDirectory = libsDir.resolve("android.${abi.abiName}").apply {
+ mkdirs()
+ }
+
+ directory.resolve("$abi/lib/$libName")
+ .copyTo(installDirectory.resolve(libName))
+
+ installDirectory.resolve("abi.json").writeText(
+ Json.encodeToString(
+ AndroidAbiMetadata(
+ abi = abi.abiName,
+ api = abi.adjustMinSdkVersion(packageData.minSdkVersion),
+ ndk = ndk.version.major,
+ stl = "c++_shared"
+ )
+ )
+ )
+ }
+
+ private fun installLicense() {
+ val src = sourceDirectory.resolve(packageData.licensePath)
+ val dest = packageDirectory.resolve("META-INF")
+ .resolve(File(packageData.licensePath).name)
+ src.copyTo(dest)
+ }
+
+ private fun createAndroidManifest() {
+ packageDirectory.resolve("AndroidManifest.xml")
+ .writeText(xml("manifest") {
+ attributes(
+ "xmlns:android" to "http://schemas.android.com/apk/res/android",
+ "package" to packageName,
+ "android:versionCode" to 1,
+ "android:versionName" to "1.0"
+ )
+
+ "uses-sdk" {
+ attributes(
+ "android:minSdkVersion" to packageData.minSdkVersion,
+ "android:targetSdkVersion" to 29
+ )
+ }
+ }.toString())
+ }
+
+ fun build() {
+ preparePackageDirectory()
+ makePackageMetadata()
+ for (module in packageData.modules) {
+ val moduleDirectory = modulesDirectory.resolve(module.name).apply {
+ mkdirs()
+ }
+
+ makeModuleMetadata(module, moduleDirectory)
+
+ if (module.includesPerAbi) {
+ TODO()
+ } else {
+ // TODO: Check that headers are actually identical across ABIs.
+ directory.resolve("${Abi.Arm}/include")
+ .copyRecursively(moduleDirectory.resolve("include"))
+ }
+
+ if (!module.headerOnly) {
+ val libsDir = moduleDirectory.resolve("libs").apply { mkdirs() }
+ for (abi in Abi.values()) {
+ installLibForAbi(module, abi, libsDir)
+ }
+ }
+ }
+
+ installLicense()
+
+ createAndroidManifest()
+ }
+}
diff --git a/buildSrc/src/main/kotlin/com/android/ndkports/PrefabSysrootPlugin.kt b/buildSrc/src/main/kotlin/com/android/ndkports/PrefabSysrootPlugin.kt
new file mode 100644
index 0000000..2828764
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/PrefabSysrootPlugin.kt
@@ -0,0 +1,60 @@
+package com.android.ndkports
+
+import com.google.prefab.api.BuildSystemInterface
+import com.google.prefab.api.Module
+import com.google.prefab.api.Package
+import com.google.prefab.api.PlatformDataInterface
+import java.io.File
+
+class PrefabSysrootPlugin(
+ override val outputDirectory: File, override val packages: List<Package>
+) : BuildSystemInterface {
+
+ override fun generate(requirements: Collection<PlatformDataInterface>) {
+ prepareOutputDirectory(outputDirectory)
+
+ for (pkg in packages) {
+ for (module in pkg.modules) {
+ for (requirement in requirements) {
+ installModule(module, requirement)
+ }
+ }
+ }
+ }
+
+ private fun installModule(
+ module: Module, requirement: PlatformDataInterface
+ ) {
+ val installDir = outputDirectory.resolve(requirement.targetTriple)
+ val includeDir = installDir.resolve("include")
+
+ if (module.isHeaderOnly) {
+ installHeaders(module.includePath.toFile(), includeDir)
+ return
+ }
+
+ val library = module.getLibraryFor(requirement)
+ installHeaders(module.includePath.toFile(), includeDir)
+ val libDir = installDir.resolve("lib").apply {
+ mkdirs()
+ }
+ library.path.toFile().apply { copyTo(libDir.resolve(name)) }
+ }
+
+ private fun installHeaders(src: File, dest: File) {
+ src.copyRecursively(dest) { file, exception ->
+ if (exception !is FileAlreadyExistsException) {
+ throw exception
+ }
+
+ if (!file.readBytes().contentEquals(exception.file.readBytes())) {
+ val path = file.relativeTo(dest)
+ throw RuntimeException(
+ "Found duplicate headers with non-equal contents: $path"
+ )
+ }
+
+ OnErrorAction.SKIP
+ }
+ }
+} \ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/com/android/ndkports/PrefabTask.kt b/buildSrc/src/main/kotlin/com/android/ndkports/PrefabTask.kt
new file mode 100644
index 0000000..d58f1fa
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/PrefabTask.kt
@@ -0,0 +1,95 @@
+package com.android.ndkports
+
+import com.google.prefab.api.Android
+import com.google.prefab.api.BuildSystemInterface
+import com.google.prefab.api.Package
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.Directory
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.file.FileCollection
+import org.gradle.api.provider.Property
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputDirectory
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.Optional
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.TaskAction
+import java.io.File
+import java.util.zip.ZipFile
+
+abstract class PrefabTask : DefaultTask() {
+ @InputFiles
+ lateinit var aars: FileCollection
+
+ @get:OutputDirectory
+ abstract val outputDirectory: DirectoryProperty
+
+ @get:OutputDirectory
+ val generatedDirectory: Provider<Directory>
+ get() = outputDirectory.dir("generated")
+
+ @get:Optional
+ @get:Input
+ abstract val generator: Property<Class<out BuildSystemInterface>>
+
+ @get:InputDirectory
+ abstract val ndkPath: DirectoryProperty
+
+ @get:Input
+ abstract val minSdkVersion: Property<Int>
+
+ private val ndk: Ndk
+ get() = Ndk(ndkPath.asFile.get())
+
+ @TaskAction
+ fun run() {
+ if (!generator.isPresent) {
+ // Creating the generated directory even if we have no generator
+ // makes it easier to write tasks that *might* consume prefab
+ // packages.
+ generatedDirectory.get().asFile.mkdirs()
+ return
+ }
+
+ val outDir = outputDirectory.get().asFile
+ val packages = mutableListOf<Package>()
+ for (aar in aars) {
+ val packagePath = outDir.resolve(aar.nameWithoutExtension)
+ extract(aar, packagePath)
+ packages.add(Package(packagePath.toPath().resolve("prefab")))
+ }
+ generateSysroot(packages, minSdkVersion.get(), ndk.version.major)
+ }
+
+ private fun extract(aar: File, extractDir: File) {
+ ZipFile(aar).use { zip ->
+ zip.entries().asSequence().forEach { entry ->
+ zip.getInputStream(entry).use { input ->
+ val outFile = extractDir.resolve(entry.name)
+ if (entry.isDirectory) {
+ outFile.mkdirs()
+ } else {
+ outFile.outputStream().use { output ->
+ input.copyTo(output)
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private fun generateSysroot(
+ packages: List<Package>, osVersion: Int, ndkVersion: Int
+ ) {
+ val generatorType = generator.get()
+ val constructor =
+ generatorType.getConstructor(File::class.java, List::class.java)
+ val buildSystemIntegration =
+ constructor.newInstance(generatedDirectory.get().asFile, packages)
+
+ buildSystemIntegration.generate(Android.Abi.values().map {
+ Android(it, osVersion, Android.Stl.CxxShared, ndkVersion)
+ })
+ }
+} \ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/com/android/ndkports/SourceExtractTask.kt b/buildSrc/src/main/kotlin/com/android/ndkports/SourceExtractTask.kt
new file mode 100644
index 0000000..4f2660f
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/SourceExtractTask.kt
@@ -0,0 +1,34 @@
+package com.android.ndkports
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.file.RegularFileProperty
+import org.gradle.api.tasks.InputFile
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.TaskAction
+
+abstract class SourceExtractTask : DefaultTask() {
+ @get:InputFile
+ abstract val source: RegularFileProperty
+
+ @get:OutputDirectory
+ abstract val outDir: DirectoryProperty
+
+ @TaskAction
+ fun run() {
+ val pb = ProcessBuilder(
+ listOf(
+ "tar",
+ "xf",
+ source.get().asFile.absolutePath,
+ "--strip-components=1"
+ )
+ ).redirectErrorStream(true).directory(outDir.get().asFile)
+
+ val result = pb.start()
+ val output = result.inputStream.bufferedReader().use { it.readText() }
+ if (result.waitFor() != 0) {
+ throw RuntimeException("Subprocess failed with:\n$output")
+ }
+ }
+} \ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/com/android/ndkports/Testing.kt b/buildSrc/src/main/kotlin/com/android/ndkports/Testing.kt
new file mode 100644
index 0000000..203e04f
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/Testing.kt
@@ -0,0 +1,151 @@
+package com.android.ndkports
+
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.SendChannel
+import kotlinx.coroutines.channels.toList
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputDirectory
+import org.gradle.api.tasks.TaskAction
+import java.io.File
+
+sealed class TestResult(val name: String, val abi: Abi) {
+ class Success(name: String, abi: Abi) : TestResult(name, abi) {
+ override fun toString(): String = "PASS $abi $name"
+ }
+
+ class Failure(name: String, abi: Abi, private val output: String) :
+ TestResult(name, abi) {
+ override fun toString(): String = "FAIL $abi $name: $output"
+ }
+}
+
+private val BASE_DEVICE_DIRECTORY = File("/data/local/tmp/ndkports")
+
+data class PushSpec(val src: File, val dest: File)
+
+class PushBuilder(val abi: Abi, val toolchain: Toolchain) {
+ val pushSpecs = mutableListOf<PushSpec>()
+
+ fun push(src: File, dest: File) = pushSpecs.add(PushSpec(src, dest))
+}
+
+data class ShellTestSpec(val name: String, val cmd: Iterable<String>)
+
+class ShellTestBuilder(val deviceDirectory: File, val abi: Abi) {
+ val runSpecs = mutableListOf<ShellTestSpec>()
+
+ fun shellTest(name: String, cmd: Iterable<String>) =
+ runSpecs.add(ShellTestSpec(name, cmd))
+}
+
+abstract class AndroidExecutableTestTask : DefaultTask() {
+ @get:InputDirectory
+ abstract val ndkPath: DirectoryProperty
+
+ private val ndk: Ndk
+ get() = Ndk(ndkPath.asFile.get())
+
+ @get:Input
+ abstract val minSdkVersion: Property<Int>
+
+ @get:Input
+ abstract val push: Property<PushBuilder.() -> Unit>
+
+ fun push(block: PushBuilder.() -> Unit) = push.set(block)
+
+ @get:Input
+ abstract val run: Property<ShellTestBuilder.() -> Unit>
+
+ fun run(block: ShellTestBuilder.() -> Unit) = run.set(block)
+
+ private fun deviceDirectoryForAbi(abi: Abi): File =
+ BASE_DEVICE_DIRECTORY.resolve(project.name).resolve(abi.toString())
+
+ private suspend fun runTests(
+ device: Device, abi: Abi, resultChannel: SendChannel<TestResult>
+ ) = coroutineScope {
+ val deviceDirectory = deviceDirectoryForAbi(abi)
+
+ val pushBlock = push.get()
+ val runBlock = run.get()
+
+ val pushBuilder =
+ PushBuilder(abi, Toolchain(ndk, abi, minSdkVersion.get()))
+ pushBuilder.pushBlock()
+ coroutineScope {
+ pushBuilder.pushSpecs.forEach {
+ launch(Dispatchers.IO) {
+ device.push(
+ it.src, deviceDirectory.resolve(it.dest)
+ )
+ }
+ }
+ }
+
+ val runBuilder = ShellTestBuilder(deviceDirectory, abi)
+ runBuilder.runBlock()
+ runBuilder.runSpecs.forEach {
+ launch(Dispatchers.IO) {
+ val result = try {
+ device.shell(it.cmd)
+ TestResult.Success(it.name, abi)
+ } catch (ex: AdbException) {
+ TestResult.Failure(it.name, abi, "${ex.cmd}\n${ex.output}")
+ }
+
+ resultChannel.send(result)
+ }
+ }
+ }
+
+ @Suppress("UnstableApiUsage")
+ @TaskAction
+ fun runTask() = runBlocking {
+ val fleet = DeviceFleet()
+ val warningChannel = Channel<String>(Channel.UNLIMITED)
+ val resultChannel = Channel<TestResult>(Channel.UNLIMITED)
+ coroutineScope {
+ for (abi in Abi.values()) {
+ launch {
+ val device = fleet.findDeviceFor(
+ abi, abi.adjustMinSdkVersion(minSdkVersion.get())
+ )
+ if (device == null) {
+ warningChannel.send(
+ "No device capable of running tests for $abi " +
+ "minSdkVersion 21"
+ )
+ return@launch
+ }
+ device.shell(
+ listOf(
+ "rm", "-rf", deviceDirectoryForAbi(abi).toString()
+ )
+ )
+ runTests(device, abi, resultChannel)
+ }
+ }
+ }
+ warningChannel.close()
+ resultChannel.close()
+
+ for (warning in warningChannel) {
+ logger.warn(warning)
+ }
+
+ val failures =
+ resultChannel.toList().filterIsInstance<TestResult.Failure>()
+ if (failures.isNotEmpty()) {
+ throw RuntimeException(
+ "Tests failed:\n${failures.joinToString("\n")}"
+ )
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/kotlin/com/android/ndkports/Toolchain.kt b/buildSrc/src/main/kotlin/com/android/ndkports/Toolchain.kt
index d42e8d1..1293ecb 100644
--- a/src/main/kotlin/com/android/ndkports/Toolchain.kt
+++ b/buildSrc/src/main/kotlin/com/android/ndkports/Toolchain.kt
@@ -29,6 +29,8 @@ class Toolchain(val ndk: Ndk, val abi: Abi, val api: Int) {
else -> "$binutilsTriple$api"
}
+ val sysrootLibs = ndk.sysrootDirectory.resolve("usr/lib/$binutilsTriple")
+
val binDir = ndk.toolchainBinDirectory
val ar = binDir.resolve("$binutilsTriple-ar")
val clang = binDir.resolve("$clangTriple-clang")
diff --git a/src/test/kotlin/com/android/ndkports/CMakeCompatibleVersionTest.kt b/buildSrc/src/test/kotlin/com/android/ndkports/CMakeCompatibleVersionTest.kt
index 7724a8e..7724a8e 100644
--- a/src/test/kotlin/com/android/ndkports/CMakeCompatibleVersionTest.kt
+++ b/buildSrc/src/test/kotlin/com/android/ndkports/CMakeCompatibleVersionTest.kt
diff --git a/src/test/kotlin/com/android/ndkports/NdkVersionTest.kt b/buildSrc/src/test/kotlin/com/android/ndkports/NdkVersionTest.kt
index 750cc52..750cc52 100644
--- a/src/test/kotlin/com/android/ndkports/NdkVersionTest.kt
+++ b/buildSrc/src/test/kotlin/com/android/ndkports/NdkVersionTest.kt
diff --git a/src/test/resources/junit-platform.properties b/buildSrc/src/test/resources/junit-platform.properties
index d265fd8..d265fd8 100644
--- a/src/test/resources/junit-platform.properties
+++ b/buildSrc/src/test/resources/junit-platform.properties
diff --git a/curl/build.gradle.kts b/curl/build.gradle.kts
new file mode 100644
index 0000000..089ef04
--- /dev/null
+++ b/curl/build.gradle.kts
@@ -0,0 +1,106 @@
+import com.android.ndkports.AutoconfPortTask
+import com.android.ndkports.CMakeCompatibleVersion
+import com.android.ndkports.PrefabSysrootPlugin
+
+val portVersion = "7.79.1"
+
+group = "com.android.ndk.thirdparty"
+version = "$portVersion${rootProject.extra.get("snapshotSuffix")}"
+
+plugins {
+ id("maven-publish")
+ id("com.android.ndkports.NdkPorts")
+}
+
+dependencies {
+ implementation(project(":openssl"))
+}
+
+ndkPorts {
+ ndkPath.set(File(project.findProperty("ndkPath") as String))
+ source.set(project.file("src.tar.gz"))
+ minSdkVersion.set(16)
+}
+
+tasks.prefab {
+ generator.set(PrefabSysrootPlugin::class.java)
+}
+
+tasks.register<AutoconfPortTask>("buildPort") {
+ autoconf {
+ args(
+ "--disable-ntlm-wb",
+ "--enable-ipv6",
+ "--with-zlib",
+ "--with-ca-path=/system/etc/security/cacerts",
+ "--with-ssl=$sysroot"
+ )
+
+ // aarch64 still defaults to bfd which transitively checks libraries.
+ // When curl is linking one of its own libraries which depends on
+ // openssl, it doesn't pass -rpath-link to be able to find the SSL
+ // libraries and fails to build because of it.
+ //
+ // TODO: Switch to lld once we're using r21.
+ env("LDFLAGS", "-fuse-ld=gold")
+ }
+}
+
+tasks.prefabPackage {
+ version.set(CMakeCompatibleVersion.parse(portVersion))
+
+ licensePath.set("COPYING")
+
+ @Suppress("UnstableApiUsage") dependencies.set(
+ mapOf(
+ "openssl" to "1.1.1k"
+ )
+ )
+
+ modules {
+ create("curl") {
+ dependencies.set(
+ listOf(
+ "//openssl:crypto", "//openssl:ssl"
+ )
+ )
+ }
+ }
+}
+
+publishing {
+ publications {
+ create<MavenPublication>("maven") {
+ from(components["prefab"])
+ pom {
+ name.set("curl")
+ description.set("The ndkports AAR for curl.")
+ url.set(
+ "https://android.googlesource.com/platform/tools/ndkports"
+ )
+ licenses {
+ license {
+ name.set("The curl License")
+ url.set("https://curl.haxx.se/docs/copyright.html")
+ distribution.set("repo")
+ }
+ }
+ developers {
+ developer {
+ name.set("The Android Open Source Project")
+ }
+ }
+ scm {
+ url.set("https://android.googlesource.com/platform/tools/ndkports")
+ connection.set("scm:git:https://android.googlesource.com/platform/tools/ndkports")
+ }
+ }
+ }
+ }
+
+ repositories {
+ maven {
+ url = uri("${rootProject.buildDir}/repository")
+ }
+ }
+}
diff --git a/curl/src.tar.gz b/curl/src.tar.gz
new file mode 100644
index 0000000..b6d3b85
--- /dev/null
+++ b/curl/src.tar.gz
Binary files differ
diff --git a/googletest/build.gradle.kts b/googletest/build.gradle.kts
new file mode 100644
index 0000000..c365519
--- /dev/null
+++ b/googletest/build.gradle.kts
@@ -0,0 +1,124 @@
+import com.android.ndkports.AndroidExecutableTestTask
+import com.android.ndkports.CMakeCompatibleVersion
+import com.android.ndkports.CMakePortTask
+
+val portVersion = "1.11.0"
+
+group = "com.android.ndk.thirdparty"
+version = "$portVersion${rootProject.extra.get("snapshotSuffix")}"
+
+plugins {
+ id("maven-publish")
+ id("com.android.ndkports.NdkPorts")
+}
+
+ndkPorts {
+ ndkPath.set(File(project.findProperty("ndkPath") as String))
+ source.set(project.file("src.tar.gz"))
+ minSdkVersion.set(16)
+}
+
+val buildTask = tasks.register<CMakePortTask>("buildPort") {
+ cmake {
+ arg("-Dgtest_build_tests=ON")
+ arg("-Dgmock_build_tests=ON")
+ }
+}
+
+tasks.prefabPackage {
+ version.set(CMakeCompatibleVersion.parse(portVersion))
+
+ modules {
+ create("gtest") {
+ static.set(true)
+ }
+ create("gtest_main") {
+ static.set(true)
+ }
+ create("gmock") {
+ static.set(true)
+ }
+ create("gmock_main") {
+ static.set(true)
+ }
+ }
+}
+
+fun findTests(directory: File) = directory.listFiles()!!.filter {
+ // There are also many tests that end with test_, but those require running
+ // Python on the device.
+ it.name.endsWith("test")
+}
+
+tasks.register<AndroidExecutableTestTask>("test") {
+ push {
+ val buildDir = buildTask.get().buildDirectoryFor(abi)
+ findTests(buildDir.resolve("googlemock")).forEach { test ->
+ push(test, File("googlemock").resolve(test.name))
+ }
+ findTests(buildDir.resolve("googletest")).forEach { test ->
+ push(test, File("googletest").resolve(test.name))
+ }
+ }
+
+ run {
+ val buildDir = buildTask.get().buildDirectoryFor(abi)
+ findTests(buildDir.resolve("googlemock")).forEach { test ->
+ shellTest(
+ test.name, listOf(
+ "cd",
+ deviceDirectory.resolve("googlemock").toString(),
+ "&&",
+ "./${test.name}"
+ )
+ )
+ }
+ findTests(buildDir.resolve("googletest")).forEach { test ->
+ shellTest(
+ test.name, listOf(
+ "cd",
+ deviceDirectory.resolve("googletest").toString(),
+ "&&",
+ "./${test.name}"
+ )
+ )
+ }
+ }
+}
+
+publishing {
+ publications {
+ create<MavenPublication>("maven") {
+ from(components["prefab"])
+ pom {
+ name.set("GoogleTest")
+ description.set("The ndkports AAR for GoogleTest.")
+ url.set(
+ "https://android.googlesource.com/platform/tools/ndkports"
+ )
+ licenses {
+ license {
+ name.set("BSD-3-Clause License")
+ url.set("https://github.com/google/googletest/blob/master/LICENSE")
+ distribution.set("repo")
+ }
+ }
+ developers {
+ developer {
+ name.set("The Android Open Source Project")
+ }
+ }
+ scm {
+ url.set("https://android.googlesource.com/platform/tools/ndkports")
+ connection.set("scm:git:https://android.googlesource.com/platform/tools/ndkports")
+ }
+ }
+ }
+ }
+
+ repositories {
+ maven {
+ url = uri("${rootProject.buildDir}/repository")
+ }
+ }
+}
diff --git a/googletest/src.tar.gz b/googletest/src.tar.gz
new file mode 100644
index 0000000..8163d74
--- /dev/null
+++ b/googletest/src.tar.gz
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 94336fc..e708b1c 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 7c4388a..da9702f 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index cccdd3d..4f906e0 100755
--- a/gradlew
+++ b/gradlew
@@ -1,5 +1,21 @@
#!/usr/bin/env sh
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
##############################################################################
##
## Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
@@ -66,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -109,10 +126,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@@ -138,19 +156,19 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
- i=$((i+1))
+ i=`expr $i + 1`
done
case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -159,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
-APP_ARGS=$(save "$@")
+APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
-fi
-
exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index f955316..107acd3 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,3 +1,19 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,28 +64,14 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/jsoncpp/build.gradle.kts b/jsoncpp/build.gradle.kts
new file mode 100644
index 0000000..29ffc66
--- /dev/null
+++ b/jsoncpp/build.gradle.kts
@@ -0,0 +1,103 @@
+import com.android.ndkports.AndroidExecutableTestTask
+import com.android.ndkports.CMakeCompatibleVersion
+import com.android.ndkports.MesonPortTask
+
+val portVersion = "1.9.5"
+
+group = "com.android.ndk.thirdparty"
+version = "$portVersion${rootProject.extra.get("snapshotSuffix")}"
+
+plugins {
+ id("maven-publish")
+ id("com.android.ndkports.NdkPorts")
+}
+
+ndkPorts {
+ ndkPath.set(File(project.findProperty("ndkPath") as String))
+ source.set(project.file("src.tar.gz"))
+ minSdkVersion.set(16)
+}
+
+tasks.extractSrc {
+ doLast {
+ // jsoncpp has a "version" file on the include path that conflicts with
+ // https://en.cppreference.com/w/cpp/header/version. Remove it so we can
+ // build.
+ outDir.get().asFile.resolve("version").delete()
+ }
+}
+
+val buildTask = tasks.register<MesonPortTask>("buildPort")
+
+tasks.prefabPackage {
+ version.set(CMakeCompatibleVersion.parse(portVersion))
+
+ modules {
+ create("jsoncpp")
+ }
+}
+
+tasks.register<AndroidExecutableTestTask>("test") {
+ push {
+ push(
+ buildTask.get().buildDirectoryFor(abi).resolve("jsoncpp_test"),
+ File("jsoncpp_test")
+ )
+ push(
+ buildTask.get().installDirectoryFor(abi)
+ .resolve("lib/libjsoncpp.so"), File("libjsoncpp.so")
+ )
+ push(
+ toolchain.sysrootLibs.resolve("libc++_shared.so"),
+ File("libc++_shared.so")
+ )
+ }
+
+ run {
+ // JsonCpp has other tests, but they require running Python on the
+ // device.
+ shellTest(
+ "jsoncpp_test", listOf(
+ "LD_LIBRARY_PATH=$deviceDirectory",
+ deviceDirectory.resolve("jsoncpp_test").toString()
+ )
+ )
+ }
+}
+
+publishing {
+ publications {
+ create<MavenPublication>("maven") {
+ from(components["prefab"])
+ pom {
+ name.set("JsonCpp")
+ description.set("The ndkports AAR for JsonCpp.")
+ url.set(
+ "https://android.googlesource.com/platform/tools/ndkports"
+ )
+ licenses {
+ license {
+ name.set("The JsonCpp License")
+ url.set("https://github.com/open-source-parsers/jsoncpp/blob/master/LICENSE")
+ distribution.set("repo")
+ }
+ }
+ developers {
+ developer {
+ name.set("The Android Open Source Project")
+ }
+ }
+ scm {
+ url.set("https://android.googlesource.com/platform/tools/ndkports")
+ connection.set("scm:git:https://android.googlesource.com/platform/tools/ndkports")
+ }
+ }
+ }
+ }
+
+ repositories {
+ maven {
+ url = uri("${rootProject.buildDir}/repository")
+ }
+ }
+}
diff --git a/jsoncpp/src.tar.gz b/jsoncpp/src.tar.gz
new file mode 100644
index 0000000..35052af
--- /dev/null
+++ b/jsoncpp/src.tar.gz
Binary files differ
diff --git a/openssl/build.gradle.kts b/openssl/build.gradle.kts
new file mode 100644
index 0000000..b7c7a48
--- /dev/null
+++ b/openssl/build.gradle.kts
@@ -0,0 +1,180 @@
+import com.android.ndkports.AdHocPortTask
+import com.android.ndkports.AndroidExecutableTestTask
+import com.android.ndkports.CMakeCompatibleVersion
+
+fun openSslVersionToCMakeVersion(openSslVersion: String): CMakeCompatibleVersion {
+ val (major, minor, microAndLetter) = openSslVersion.split(".")
+ val letter = microAndLetter.last()
+ val micro = microAndLetter.substringBefore(letter)
+ val tweak = if (letter.isDigit()) {
+ // 1.1.1 is 1.1.1.0.
+ 0
+ } else {
+ // 1.1.1a is 1.1.1.1.
+ letter.toInt() - 'a'.toInt() + 1
+ }
+
+ return CMakeCompatibleVersion(
+ major.toInt(), minor.toInt(), micro.toInt(), tweak
+ )
+}
+
+val portVersion = "1.1.1l"
+val prefabVersion = openSslVersionToCMakeVersion(portVersion)
+
+group = "com.android.ndk.thirdparty"
+version = "$portVersion${rootProject.extra.get("snapshotSuffix")}"
+
+plugins {
+ id("maven-publish")
+ id("com.android.ndkports.NdkPorts")
+}
+
+ndkPorts {
+ ndkPath.set(File(project.findProperty("ndkPath") as String))
+ source.set(project.file("src.tar.gz"))
+ minSdkVersion.set(16)
+}
+
+val buildTask = tasks.register<AdHocPortTask>("buildPort") {
+ builder {
+ run {
+ args(
+ sourceDirectory.resolve("Configure").absolutePath,
+ "android-${toolchain.abi.archName}",
+ "-D__ANDROID_API__=${toolchain.api}",
+ "--prefix=${installDirectory.absolutePath}",
+ "--openssldir=${installDirectory.absolutePath}",
+ "no-sctp",
+ "shared"
+ )
+
+ env("ANDROID_NDK", toolchain.ndk.path.absolutePath)
+ env("PATH", "${toolchain.binDir}:${System.getenv("PATH")}")
+ }
+
+ run {
+ args("make", "-j$ncpus", "SHLIB_EXT=.so")
+
+ env("ANDROID_NDK", toolchain.ndk.path.absolutePath)
+ env("PATH", "${toolchain.binDir}:${System.getenv("PATH")}")
+ }
+
+ run {
+ args("make", "install_sw", "SHLIB_EXT=.so")
+
+ env("ANDROID_NDK", toolchain.ndk.path.absolutePath)
+ env("PATH", "${toolchain.binDir}:${System.getenv("PATH")}")
+ }
+ }
+}
+
+tasks.prefabPackage {
+ version.set(prefabVersion)
+
+ modules {
+ create("crypto")
+ create("ssl")
+ }
+}
+
+tasks.register<AndroidExecutableTestTask>("test") {
+ val srcDir = tasks.extractSrc.get().outDir.asFile.get()
+ val testSrc = srcDir.resolve("test/ssl-tests")
+ val deviceTestRelPath = File("testconf")
+
+ val unsupportedTests = listOf(
+ // This test is empty and appears to just be broken in 1.1.1k.
+ "16-certstatus.conf",
+ // zlib support is not enabled.
+ "22-compression.conf",
+ // Android does not support SCTP sockets and this test requires them.
+ "29-dtls-sctp-label-bug.conf"
+ )
+
+ push {
+ val ignoredExtensions = listOf("o", "d")
+ val buildDirectory = buildTask.get().buildDirectoryFor(abi)
+ push(
+ srcDir.resolve("test/ct/log_list.conf"), File("log_list.conf")
+ )
+ for (file in buildDirectory.walk()) {
+ if (!file.isFile) {
+ continue
+ }
+
+ if (file.extension in ignoredExtensions) {
+ continue
+ }
+
+ push(file, file.relativeTo(buildDirectory))
+ }
+ for (file in testSrc.walk()) {
+ if (file.extension == "conf") {
+ push(
+ file, deviceTestRelPath.resolve(file.relativeTo(testSrc))
+ )
+ }
+ }
+ push(srcDir.resolve("test/certs"), File("certs"))
+ }
+
+ run {
+ // https://github.com/openssl/openssl/blob/master/test/README.ssltest.md
+ val sslTest = deviceDirectory.resolve("test/ssl_test")
+ val ctlogFile = deviceDirectory.resolve("log_list.conf")
+ val testCertDir = deviceDirectory.resolve("certs")
+ for (file in testSrc.walk()) {
+ val test = deviceDirectory.resolve(deviceTestRelPath)
+ .resolve(file.relativeTo(testSrc))
+ if (file.extension == "conf" && file.name !in unsupportedTests) {
+ shellTest(
+ file.relativeTo(testSrc).toString(), listOf(
+ "LD_LIBRARY_PATH=$deviceDirectory",
+ "CTLOG_FILE=$ctlogFile",
+ "TEST_CERTS_DIR=$testCertDir",
+ sslTest.toString(),
+ test.toString()
+ )
+ )
+ }
+ }
+ }
+}
+
+publishing {
+ publications {
+ create<MavenPublication>("maven") {
+ from(components["prefab"])
+ pom {
+ name.set("OpenSSL")
+ description.set("The ndkports AAR for OpenSSL.")
+ url.set(
+ "https://android.googlesource.com/platform/tools/ndkports"
+ )
+ licenses {
+ license {
+ name.set("Dual OpenSSL and SSLeay License")
+ url.set("https://www.openssl.org/source/license-openssl-ssleay.txt")
+ distribution.set("repo")
+ }
+ }
+ developers {
+ developer {
+ name.set("The Android Open Source Project")
+ }
+ }
+ scm {
+ url.set("https://android.googlesource.com/platform/tools/ndkports")
+ connection.set("scm:git:https://android.googlesource.com/platform/tools/ndkports")
+ }
+ }
+ }
+ }
+
+ repositories {
+ maven {
+ url = uri("${rootProject.buildDir}/repository")
+ }
+ }
+}
diff --git a/ports/openssl/src.tar.gz b/openssl/src.tar.gz
index e768f9e..81be7f9 100644
--- a/ports/openssl/src.tar.gz
+++ b/openssl/src.tar.gz
Binary files differ
diff --git a/ports/curl/port.kts b/ports/curl/port.kts
deleted file mode 100644
index a870a86..0000000
--- a/ports/curl/port.kts
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ndkports
-
-import java.io.File
-
-object : AutoconfPort() {
- override val name = "curl"
- override val version = "7.69.1"
- override val mavenVersion = "$version-alpha-1"
- override val licensePath = "COPYING"
-
- override val license = License(
- "The curl License", "https://curl.haxx.se/docs/copyright.html"
- )
-
- override val dependencies = listOf("openssl")
-
- override val modules = listOf(
- Module(
- "curl",
- dependencies = listOf("//openssl:crypto", "//openssl:ssl")
- )
- )
-
- override fun configureArgs(
- workingDirectory: File,
- toolchain: Toolchain
- ): List<String> {
- val sslPrefix = installDirectoryForPort(
- "openssl",
- workingDirectory,
- toolchain
- ).absolutePath
- return listOf(
- "--disable-ntlm-wb",
- "--enable-ipv6",
- "--with-zlib",
- "--with-ca-path=/system/etc/security/cacerts",
- "--with-ssl=$sslPrefix"
- )
- }
-
- override fun configureEnv(
- workingDirectory: File,
- toolchain: Toolchain
- ): Map<String, String> = mapOf(
- // aarch64 still defaults to bfd which transitively checks libraries.
- // When curl is linking one of its own libraries which depends on
- // openssl, it doesn't pass -rpath-link to be able to find the SSL
- // libraries and fails to build because of it.
- //
- // TODO: Switch to lld once we're using r21.
- "LDFLAGS" to "-fuse-ld=gold"
- )
-}
diff --git a/ports/curl/src.tar.gz b/ports/curl/src.tar.gz
deleted file mode 100644
index b0da690..0000000
--- a/ports/curl/src.tar.gz
+++ /dev/null
Binary files differ
diff --git a/ports/jsoncpp/port.kts b/ports/jsoncpp/port.kts
deleted file mode 100644
index 8a3e1ba..0000000
--- a/ports/jsoncpp/port.kts
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ndkports
-
-import java.io.File
-
-object : MesonPort() {
- override val name = "jsoncpp"
- override val version = "1.8.4"
- override val mavenVersion = "$version-alpha-1"
-
- override val license = License(
- "The JsonCpp License",
- "https://github.com/open-source-parsers/jsoncpp/blob/master/LICENSE"
- )
-
- override val modules = listOf(
- Module("jsoncpp")
- )
-
- override fun extractSource(
- sourceTarball: File,
- sourceDirectory: File,
- workingDirectory: File
- ): Result<Unit, String> =
- super.extractSource(sourceTarball, sourceDirectory, workingDirectory)
- .onSuccess {
- // jsoncpp has a "version" file on the include path that
- // conflicts with
- // https://en.cppreference.com/w/cpp/header/version. Remove it
- // so we can build.
- sourceDirectory.resolve("version").delete()
- }
-}
diff --git a/ports/jsoncpp/src.tar.gz b/ports/jsoncpp/src.tar.gz
deleted file mode 100644
index 7f3cd4b..0000000
--- a/ports/jsoncpp/src.tar.gz
+++ /dev/null
Binary files differ
diff --git a/ports/openssl/port.kts b/ports/openssl/port.kts
deleted file mode 100644
index 45b5206..0000000
--- a/ports/openssl/port.kts
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ndkports
-
-import java.io.File
-
-object : Port() {
- override val name = "openssl"
- override val version = "1.1.1g"
- override val mavenVersion = "$version-alpha-1"
- override val prefabVersion = CMakeCompatibleVersion(1, 1, 1, 7)
-
- override val license = License(
- "Dual OpenSSL and SSLeay License",
- "https://www.openssl.org/source/license-openssl-ssleay.txt"
- )
-
- override val modules = listOf(
- Module("crypto"),
- Module("ssl")
- )
-
- override fun configure(
- toolchain: Toolchain,
- sourceDirectory: File,
- buildDirectory: File,
- installDirectory: File,
- workingDirectory: File
- ): Result<Unit, String> {
- buildDirectory.mkdirs()
- return executeProcessStep(
- listOf(
- sourceDirectory.resolve("Configure").absolutePath,
- "android-${toolchain.abi.archName}",
- "-D__ANDROID_API__=${toolchain.api}",
- "--prefix=${installDirectory.absolutePath}",
- "--openssldir=${installDirectory.absolutePath}",
- "shared"
- ),
- buildDirectory,
- additionalEnvironment = mapOf(
- "ANDROID_NDK" to toolchain.ndk.path.absolutePath,
- "PATH" to "${toolchain.binDir}:${System.getenv("PATH")}"
- )
- )
- }
-
- override fun build(
- toolchain: Toolchain,
- buildDirectory: File
- ): Result<Unit, String> =
- executeProcessStep(
- listOf(
- "make",
- "-j$ncpus",
- "SHLIB_EXT=.so"
- ), buildDirectory,
- additionalEnvironment = mapOf(
- "ANDROID_NDK" to toolchain.ndk.path.absolutePath,
- "PATH" to "${toolchain.binDir}:${System.getenv("PATH")}"
- )
- )
-
- override fun install(
- toolchain: Toolchain,
- buildDirectory: File,
- installDirectory: File
- ): Result<Unit, String> =
- executeProcessStep(
- listOf("make", "install_sw", "SHLIB_EXT=.so"), buildDirectory,
- additionalEnvironment = mapOf(
- "ANDROID_NDK" to toolchain.ndk.path.absolutePath,
- "PATH" to "${toolchain.binDir}:${System.getenv("PATH")}"
- )
- )
-}
diff --git a/scripts/build.sh b/scripts/build.sh
deleted file mode 100755
index e7c16b6..0000000
--- a/scripts/build.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-set -e
-docker build -t ndkports .
-docker run --rm -v $(pwd):/src ndkports
diff --git a/scripts/build_release.sh b/scripts/build_release.sh
new file mode 100755
index 0000000..f99e223
--- /dev/null
+++ b/scripts/build_release.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+set -e
+docker build -t ndkports .
+# We need to specify the full argument list for gradle explicitly because
+# there's no way to append to docker's CMD. This should be kept the same as the
+# default, but adding -Prelease.
+docker run --rm -v $(pwd):/src ndkports \
+ --stacktrace -PndkPath=/ndk -Prelease release
diff --git a/scripts/build_snapshot.sh b/scripts/build_snapshot.sh
new file mode 100755
index 0000000..4c9d767
--- /dev/null
+++ b/scripts/build_snapshot.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+set -e
+docker build -t ndkports .
+# Default command for the docker image handles the NDK location, --stacktrace,
+# task list, etc.
+docker run --rm -v $(pwd):/src ndkports
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 4549d2e..726326c 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -8,4 +8,9 @@ pluginManagement {
}
}
}
-} \ No newline at end of file
+}
+
+include("curl")
+include("googletest")
+include("jsoncpp")
+include("openssl")
diff --git a/src/main/kotlin/com/android/ndkports/Abi.kt b/src/main/kotlin/com/android/ndkports/Abi.kt
deleted file mode 100644
index 58981a2..0000000
--- a/src/main/kotlin/com/android/ndkports/Abi.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ndkports
-
-enum class Abi(val archName: String, val abiName: String) {
- Arm("arm", "armeabi-v7a"),
- Arm64("arm64", "arm64-v8a"),
- X86("x86", "x86"),
- X86_64("x86_64", "x86_64"),
-} \ No newline at end of file
diff --git a/src/main/kotlin/com/android/ndkports/Cli.kt b/src/main/kotlin/com/android/ndkports/Cli.kt
deleted file mode 100644
index e2a5879..0000000
--- a/src/main/kotlin/com/android/ndkports/Cli.kt
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ndkports
-
-import com.github.ajalt.clikt.core.CliktCommand
-import com.github.ajalt.clikt.parameters.arguments.argument
-import com.github.ajalt.clikt.parameters.arguments.multiple
-import com.github.ajalt.clikt.parameters.arguments.validate
-import com.github.ajalt.clikt.parameters.options.convert
-import com.github.ajalt.clikt.parameters.options.default
-import com.github.ajalt.clikt.parameters.options.flag
-import com.github.ajalt.clikt.parameters.options.option
-import com.github.ajalt.clikt.parameters.options.required
-import com.github.ajalt.clikt.parameters.types.file
-import de.swirtz.ktsrunner.objectloader.KtsObjectLoader
-import java.io.File
-import java.io.FileNotFoundException
-import java.lang.RuntimeException
-import kotlin.system.exitProcess
-
-class Cli : CliktCommand(help = "ndkports") {
- private val outDir: File by option(
- "-o",
- "--out",
- help = "Build directory."
- ).file().default(File("out"))
-
- private val publishToMavenLocal: Boolean by option(
- help = "Publish AARs to the local Maven repository (~/.m2/repository)"
- ).flag()
-
- private val packages: List<String> by argument(
- help = "Names of packages to build."
- ).multiple().validate {
- require(it.isNotEmpty()) { "must provide at least one package" }
- }
-
- private val ndk: Ndk by option().convert { Ndk(File(it)) }.required()
-
- private fun portDirectoryFor(name: String): File =
- File("ports").resolve(name)
-
- private fun loadPort(name: String): Port {
- val portDir = portDirectoryFor(name).also {
- if (!it.exists()) {
- throw FileNotFoundException("Could not find ${it.path}")
- }
- }
-
- val portFile = portDir.resolve("port.kts").also {
- if (!it.exists()) {
- throw FileNotFoundException("Could not find ${it.path}")
- }
- }
-
- return KtsObjectLoader().load(portFile.reader())
- }
-
- override fun run() {
- println("Building packages: ${packages.joinToString(", ")}")
- val portsByName = packages.map { loadPort(it) }.associateBy { it.name }
- for (port in portsByName.values) {
- val workingDirectory =
- outDir.resolve(port.name).also { it.mkdirs() }
-
- val sourceDirectory = workingDirectory.resolve("src")
- val sourceTarball =
- portDirectoryFor(port.name).resolve("src.tar.gz")
-
- port.extractSource(sourceTarball, sourceDirectory, workingDirectory)
-
- val apiForAbi = mapOf(
- Abi.Arm to 16,
- Abi.Arm64 to 21,
- Abi.X86 to 16,
- Abi.X86_64 to 21
- )
- for (abi in Abi.values()) {
- val api = apiForAbi.getOrElse(abi) {
- throw RuntimeException(
- "No API level specified for ${abi.abiName}"
- )
- }
- val toolchain = Toolchain(ndk, abi, api)
-
- val buildDirectory = workingDirectory.resolve("build/$abi")
- val installDirectory = installDirectoryForPort(
- port.name, workingDirectory, toolchain
- )
-
- port.run(
- toolchain,
- sourceDirectory,
- buildDirectory,
- installDirectory,
- workingDirectory
- ).onFailure {
- println(it)
- exitProcess(1)
- }
- }
-
- PrefabPackageBuilder(
- port,
- workingDirectory,
- sourceDirectory,
- publishToMavenLocal,
- ndk,
- apiForAbi,
- portsByName
- ).build()
- }
- }
-}
-
-fun main(args: Array<String>) {
- Cli().main(args)
-} \ No newline at end of file
diff --git a/src/main/kotlin/com/android/ndkports/License.kt b/src/main/kotlin/com/android/ndkports/License.kt
deleted file mode 100644
index 8ec639f..0000000
--- a/src/main/kotlin/com/android/ndkports/License.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ndkports
-
-data class License(val name: String, val url: String) \ No newline at end of file
diff --git a/src/main/kotlin/com/android/ndkports/Port.kt b/src/main/kotlin/com/android/ndkports/Port.kt
deleted file mode 100644
index 2e0433f..0000000
--- a/src/main/kotlin/com/android/ndkports/Port.kt
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ndkports
-
-import java.io.File
-
-@Suppress("unused")
-fun executeProcessStep(
- args: List<String>,
- workingDirectory: File,
- additionalEnvironment: Map<String, String>? = null
-): Result<Unit, String> {
- val pb = ProcessBuilder(args)
- .redirectOutput(ProcessBuilder.Redirect.INHERIT)
- .redirectError(ProcessBuilder.Redirect.INHERIT)
- .directory(workingDirectory)
-
- if (additionalEnvironment != null) {
- pb.environment().putAll(additionalEnvironment)
- }
-
- return pb.start()
- .waitFor().let {
- if (it == 0) {
- Result.Ok(Unit)
- } else {
- Result.Error("Process failed with exit code $it")
- }
- }
-}
-
-fun installDirectoryForPort(
- name: String,
- workingDirectory: File,
- toolchain: Toolchain
-): File = workingDirectory.parentFile.resolve("$name/install/${toolchain.abi}")
-
-/**
- * A module exported by the package.
- *
- * As currently implemented by ndkports, one module is exactly one library.
- * Prefab supports header-only libraries, but ndkports does not support these
- * yet.
- *
- * Static libraries are not currently supported by ndkports.
- *
- * @property[name] The name of the module. Note that currently the name of the
- * installed library file must be exactly `lib$name.so`.
- * @property[includesPerAbi] Set to true if a different set of headers should be
- * exposed per-ABI. Not currently implemented.
- * @property[dependencies] A list of other modules required by this module, in
- * the format described by https://google.github.io/prefab/.
- */
-data class Module(
- val name: String,
- val includesPerAbi: Boolean = false,
- val dependencies: List<String> = emptyList()
-)
-
-/**
- * The base class for all ports.
- */
-abstract class Port {
- /**
- * The name of the port. Will be used as the package name in prefab.json.
- */
- abstract val name: String
-
- /**
- * The version of the package.
- *
- * Used as the default for [prefabVersion] and [mavenVersion] when
- * appropriate.
- */
- abstract val version: String
-
- /**
- * The version to encode in the prefab.json.
- *
- * This version must be compatible with CMake's `find_package` for
- * config-style packages. This means that it must be one to four decimal
- * separated integers. No other format is allowed.
- *
- * If not set, the default is [version] as interpreted by
- * [CMakeCompatibleVersion.parse].
- *
- * For example, OpenSSL 1.1.1g will set this value to
- * `CMakeCompatibleVersion(1, 1, 1, 7)`.
- */
- open val prefabVersion: CMakeCompatibleVersion
- get() = CMakeCompatibleVersion.parse(version)
-
- /**
- * The version to use for the maven package.
- *
- * This field allows versioning the maven package differently from the
- * package itself, which is sometimes necessary given CMake's strict version
- * format requirements.
- *
- * If not set, the default is [version].
- *
- * For example, this could be set to `"$name-$version-alpha-1"` to
- * distribute an alpha of the package.
- */
- open val mavenVersion: String
- get() = version
-
- /**
- * The relative path to the license file of this package.
- *
- * This file will be packaged in the AAR in the META-INF directory.
- */
- open val licensePath: String = "LICENSE"
-
- /**
- * A description of the license (name and URL) for use in the pom.xml.
- */
- abstract val license: License
-
- /**
- * A list of dependencies for this package.
- *
- * For example, curl depends on `listOf("openssl")`.
- */
- open val dependencies: List<String> = emptyList()
-
- /**
- * A list of modules exported by this package.
- */
- abstract val modules: List<Module>
-
- /**
- * The number of CPUs available for building.
- *
- * May be passed to the build system if required.
- */
- protected val ncpus = Runtime.getRuntime().availableProcessors()
-
- fun run(
- toolchain: Toolchain,
- sourceDirectory: File,
- buildDirectory: File,
- installDirectory: File,
- workingDirectory: File
- ): Result<Unit, String> {
- configure(
- toolchain,
- sourceDirectory,
- buildDirectory,
- installDirectory,
- workingDirectory
- ).onFailure { return Result.Error(it) }
-
- build(toolchain, buildDirectory).onFailure { return Result.Error(it) }
-
- install(
- toolchain,
- buildDirectory,
- installDirectory
- ).onFailure { return Result.Error(it) }
-
- return Result.Ok(Unit)
- }
-
- /**
- * Overridable build step for extracting the source package.
- *
- * @param[sourceTarball] The path to the source tarball.
- * @param[sourceDirectory] The destination directory for the extracted
- * source.
- * @param[workingDirectory] The working top-level directory for this
- * package.
- * @return A [Result<Unit, String>][Result] describing the result of the
- * operation. On failure, [Result.Error<String>][Result.Error] containing an
- * error message is returned.
- */
- open fun extractSource(
- sourceTarball: File,
- sourceDirectory: File,
- workingDirectory: File
- ): Result<Unit, String> {
- sourceDirectory.mkdirs()
- return executeProcessStep(
- listOf(
- "tar",
- "xf",
- sourceTarball.absolutePath,
- "--strip-components=1"
- ), sourceDirectory
- )
- }
-
- /**
- * Overridable build step for configuring the build.
- *
- * Any pre-build steps should be run here.
- *
- * In an autoconf build, this runs `configure`.
- *
- * @param[toolchain] The toolchain used for this build.
- * @param[sourceDirectory] The directory containing the extracted package
- * source.
- * @param[buildDirectory] The directory to use for building.
- * @param[installDirectory] The destination directory for this package's
- * installed headers and libraries.
- * @param[workingDirectory] The top-level working directory for this
- * package.
- * @return A [Result<Unit, String>][Result] describing the result of the
- * operation. On failure, [Result.Error<String>][Result.Error] containing an
- * error message is returned.
- */
- open fun configure(
- toolchain: Toolchain,
- sourceDirectory: File,
- buildDirectory: File,
- installDirectory: File,
- workingDirectory: File
- ): Result<Unit, String> = Result.Ok(Unit)
-
- /**
- * Overridable build step for building the package.
- *
- * In an autoconf build, this runs `make`.
- *
- * @param[toolchain] The toolchain used for this build.
- * @param[buildDirectory] The directory to use for building.
- * @return A [Result<Unit, String>][Result] describing the result of the
- * operation. On failure, [Result.Error<String>][Result.Error] containing an
- * error message is returned.
- */
- open fun build(
- toolchain: Toolchain,
- buildDirectory: File
- ): Result<Unit, String> = Result.Ok(Unit)
-
- /**
- * Overridable build step for installing built artifacts for packaging.
- *
- * The install step is expected to install headers and libraries to the
- * [installDirectory] with the following layout:
- *
- * [installDirectory]
- * include/
- * <package headers>
- * lib/
- * <package libraries>
- *
- * A matching `lib${module.name}.so` must be present in the `lib` directory
- * for every item in [modules].
- *
- * Note that it is expected for all modules to use the same headers. This is
- * currently the case for all ports currently maintained, but could change
- * in the future.
- *
- * In an autoconf build, this runs `make install`.
- *
- * @param[toolchain] The toolchain used for this build.
- * @param[buildDirectory] The directory containing build artifacts.
- * @param[installDirectory] The destination directory for this package's
- * installed headers and libraries.
- * @return A [Result<Unit, String>][Result] describing the result of the
- * operation. On failure, [Result.Error<String>][Result.Error] containing an
- * error message is returned.
- */
- open fun install(
- toolchain: Toolchain,
- buildDirectory: File,
- installDirectory: File
- ): Result<Unit, String> = Result.Ok(Unit)
-} \ No newline at end of file
diff --git a/src/main/kotlin/com/android/ndkports/PrefabPackageBuilder.kt b/src/main/kotlin/com/android/ndkports/PrefabPackageBuilder.kt
deleted file mode 100644
index 1a58f5a..0000000
--- a/src/main/kotlin/com/android/ndkports/PrefabPackageBuilder.kt
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ndkports
-
-import com.google.prefab.api.AndroidAbiMetadata
-import com.google.prefab.api.ModuleMetadataV1
-import com.google.prefab.api.PackageMetadataV1
-import kotlinx.serialization.json.Json
-import kotlinx.serialization.stringify
-import org.apache.maven.model.Dependency
-import org.apache.maven.model.Developer
-import org.apache.maven.model.License
-import org.apache.maven.model.Scm
-import org.apache.maven.model.io.DefaultModelWriter
-import org.apache.maven.project.MavenProject
-import org.redundent.kotlin.xml.xml
-import java.io.File
-
-class PrefabPackageBuilder(
- private val port: Port,
- private val directory: File,
- private val sourceDirectory: File,
- private val publishToMavenLocal: Boolean,
- private val ndk: Ndk,
- private val abiToApiMap: Map<Abi, Int>,
- private val portsByName: Map<String, Port>
-) {
- private val packageDirectory = directory.resolve("aar")
- private val prefabDirectory = packageDirectory.resolve("prefab")
- private val modulesDirectory = prefabDirectory.resolve("modules")
-
- private val packageComponents = listOf(
- "com",
- "android",
- "ndk",
- "thirdparty",
- port.name
- )
-
- private val packageName = packageComponents.joinToString(".")
- private val groupComponents = packageComponents.dropLast(1)
- private val groupId = groupComponents.joinToString(".")
- private val artifactId = packageComponents.last()
-
- private val mavenProject = MavenProject().also {
- it.name = port.name
- it.description = "The ndkports AAR for ${port.name}."
- it.url = "https://android.googlesource.com/platform/tools/ndkports"
- it.groupId = groupId
- it.artifactId = artifactId
- it.version = port.mavenVersion
- it.packaging = "aar"
- it.licenses = listOf(
- License().also { license ->
- license.name = port.license.name
- license.url = port.license.url
- license.distribution = "repo"
- }
- )
- it.developers = listOf(
- Developer().also { developer ->
- developer.name = "The Android Open Source Project"
- }
- )
- it.scm = Scm().also { scm ->
- scm.url = "https://android.googlesource.com/platform/tools/ndkports"
- scm.connection = "scm:git:https://android.googlesource.com/platform/tools/ndkports"
- }
- it.dependencies = port.dependencies.map { depName ->
- val depPort = portsByName[depName] ?: throw RuntimeException(
- "${port.name} depends on unknown port: $depName"
- )
- Dependency().also { dep ->
- dep.artifactId = depPort.name
- dep.groupId = groupId
- dep.version = depPort.mavenVersion
- dep.type = "aar"
- // TODO: Make this an option in the Port.
- // We currently only have one dependency from curl to OpenSSL,
- // and that's (from the perspective of the AAR consumer), a
- // runtime dependency. If we ever have compile dependencies,
- // we'll want to make it possible for each port to customize its
- // scope.
- dep.scope = "runtime"
- }
- }
- // TODO: Issue management?
- }
-
- private fun preparePackageDirectory() {
- if (packageDirectory.exists()) {
- packageDirectory.deleteRecursively()
- }
- modulesDirectory.mkdirs()
- }
-
- private fun makePackageMetadata() {
- prefabDirectory.resolve("prefab.json").writeText(
- Json.stringify(
- PackageMetadataV1(
- port.name,
- schemaVersion = 1,
- dependencies = port.dependencies,
- version = port.prefabVersion.toString()
- )
- )
- )
- }
-
- private fun makeModuleMetadata(module: Module, moduleDirectory: File) {
- moduleDirectory.resolve("module.json").writeText(
- Json.stringify(
- ModuleMetadataV1(
- exportLibraries = module.dependencies
- )
- )
- )
- }
-
- private fun installLibForAbi(module: Module, abi: Abi, libsDir: File) {
- val libName = "lib${module.name}.so"
- val installDirectory = libsDir.resolve("android.${abi.abiName}").apply {
- mkdirs()
- }
-
- directory.resolve("install/$abi/lib/$libName")
- .copyTo(installDirectory.resolve(libName))
-
- val api = abiToApiMap.getOrElse(abi) {
- throw RuntimeException(
- "No API level specified for ${abi.abiName}"
- )
- }
-
- installDirectory.resolve("abi.json").writeText(
- Json.stringify(
- AndroidAbiMetadata(
- abi = abi.abiName,
- api = api,
- ndk = ndk.version.major,
- stl = "c++_shared"
- )
- )
- )
- }
-
- private fun installLicense() {
- val src = sourceDirectory.resolve(port.licensePath)
- val dest = packageDirectory.resolve("META-INF")
- .resolve(File(port.licensePath).name)
- src.copyTo(dest)
- }
-
- private fun createAndroidManifest() {
- packageDirectory.resolve("AndroidManifest.xml")
- .writeText(xml("manifest") {
- attributes(
- "xmlns:android" to "http://schemas.android.com/apk/res/android",
- "package" to packageName,
- "android:versionCode" to 1,
- "android:versionName" to "1.0"
- )
-
- "uses-sdk" {
- attributes(
- "android:minSdkVersion" to 16,
- "android:targetSdkVersion" to 29
- )
- }
- }.toString())
- }
-
- private fun createPom(pomFile: File) {
- DefaultModelWriter().write(pomFile, null, mavenProject.model)
- }
-
- private fun installToLocalMaven(archive: File, pomFile: File) {
- val pb = ProcessBuilder(
- listOf(
- "mvn",
- "install:install-file",
- "-Dfile=$archive",
- "-DpomFile=$pomFile"
- )
- )
- .redirectOutput(ProcessBuilder.Redirect.INHERIT)
- .redirectError(ProcessBuilder.Redirect.INHERIT)
-
- return pb.start()
- .waitFor().let {
- if (it != 0) {
- throw RuntimeException(
- "Failed to install archive to local maven " +
- "repository: $archive $pomFile"
- )
- }
- }
- }
-
- private fun createArchive() {
- val archive = directory.resolve("${port.name}-${port.mavenVersion}.aar")
- val pomFile = directory.resolve("${port.name}-${port.mavenVersion}.pom")
- createZipFromDirectory(archive, packageDirectory)
- createPom(pomFile)
- if (publishToMavenLocal) {
- installToLocalMaven(archive, pomFile)
- }
- }
-
- fun build() {
- preparePackageDirectory()
- makePackageMetadata()
- for (module in port.modules) {
- val moduleDirectory = modulesDirectory.resolve(module.name).apply {
- mkdirs()
- }
-
- makeModuleMetadata(module, moduleDirectory)
-
- if (module.includesPerAbi) {
- TODO()
- } else {
- // TODO: Perform sanity check.
- directory.resolve("install/${Abi.Arm}/include")
- .copyRecursively(moduleDirectory.resolve("include"))
- }
-
- val libsDir = moduleDirectory.resolve("libs").apply { mkdirs() }
- for (abi in Abi.values()) {
- installLibForAbi(module, abi, libsDir)
- }
- }
-
- installLicense()
-
- createAndroidManifest()
- createArchive()
- }
-}
diff --git a/src/main/kotlin/com/android/ndkports/Zip.kt b/src/main/kotlin/com/android/ndkports/Zip.kt
deleted file mode 100644
index a23ff90..0000000
--- a/src/main/kotlin/com/android/ndkports/Zip.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ndkports
-
-import java.io.File
-import java.io.FileInputStream
-import java.io.FileOutputStream
-import java.util.zip.ZipEntry
-import java.util.zip.ZipOutputStream
-
-private fun zipDirectory(name: String, zipOut: ZipOutputStream) {
- zipOut.putNextEntry(ZipEntry("$name/"))
- zipOut.closeEntry()
-}
-
-private fun zipFile(file: File, name: String, zipOut: ZipOutputStream) {
- zipOut.putNextEntry(ZipEntry(name))
- FileInputStream(file).use {
- it.copyTo(zipOut)
- }
-}
-
-private fun zip(file: File, name: String, zipOut: ZipOutputStream) {
- if (file.isDirectory) {
- zipDirectory(name, zipOut)
- } else {
- zipFile(file, name, zipOut)
- }
-}
-
-fun createZipFromDirectory(output: File, input: File) {
- FileOutputStream(output).use { fos ->
- ZipOutputStream(fos).use { zos ->
- input.walk().filter { it != input }.forEach {
- zip(it, it.relativeTo(input).path, zos)
- }
- }
- }
-} \ No newline at end of file
diff --git a/src/test/kotlin/com/android/ndkports/ResultTest.kt b/src/test/kotlin/com/android/ndkports/ResultTest.kt
deleted file mode 100644
index 0abef18..0000000
--- a/src/test/kotlin/com/android/ndkports/ResultTest.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ndkports
-
-import kotlin.test.Test
-import kotlin.test.assertEquals
-import kotlin.test.fail
-
-class ResultTest {
- @Test
- fun `onFailure executes block on failure`() {
- val result = Result.Error("foo")
- result.onFailure {
- assertEquals("foo", it)
- return
- }
- fail()
- }
-
- @Test
- fun `onFailure does not execute block on success`() {
- val result = Result.Ok(Unit)
- result.onFailure { fail() }
- }
-
- @Test
- fun `onFailure returns same result object`() {
- val result = Result.Error(Unit)
- assertEquals(result, result.onFailure {})
- }
-
- @Test
- fun `onSuccess executes block on success`() {
- val result = Result.Ok("foo")
- result.onSuccess {
- assertEquals("foo", it)
- return
- }
- fail()
- }
-
- @Test
- fun `onSuccess does not execute block on failure`() {
- val result = Result.Error(Unit)
- result.onSuccess { fail() }
- }
-
- @Test
- fun `onSuccess returns same result object`() {
- val result = Result.Ok(Unit)
- assertEquals(result, result.onSuccess {})
- }
-} \ No newline at end of file