Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2019 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.android.ndkports |
| 18 | |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 19 | import java.io.File |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 20 | |
| 21 | @Suppress("unused") |
| 22 | fun executeProcessStep( |
| 23 | args: List<String>, |
| 24 | workingDirectory: File, |
| 25 | additionalEnvironment: Map<String, String>? = null |
| 26 | ): Result<Unit, String> { |
| 27 | val pb = ProcessBuilder(args) |
| 28 | .redirectOutput(ProcessBuilder.Redirect.INHERIT) |
| 29 | .redirectError(ProcessBuilder.Redirect.INHERIT) |
| 30 | .directory(workingDirectory) |
| 31 | |
| 32 | if (additionalEnvironment != null) { |
| 33 | pb.environment().putAll(additionalEnvironment) |
| 34 | } |
| 35 | |
| 36 | return pb.start() |
| 37 | .waitFor().let { |
| 38 | if (it == 0) { |
| 39 | Result.Ok(Unit) |
| 40 | } else { |
| 41 | Result.Error("Process failed with exit code $it") |
| 42 | } |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | fun installDirectoryForPort( |
| 47 | name: String, |
| 48 | workingDirectory: File, |
| 49 | toolchain: Toolchain |
| 50 | ): File = workingDirectory.parentFile.resolve("$name/install/${toolchain.abi}") |
| 51 | |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 52 | /** |
| 53 | * A module exported by the package. |
| 54 | * |
| 55 | * As currently implemented by ndkports, one module is exactly one library. |
| 56 | * Prefab supports header-only libraries, but ndkports does not support these |
| 57 | * yet. |
| 58 | * |
| 59 | * Static libraries are not currently supported by ndkports. |
| 60 | * |
| 61 | * @property[name] The name of the module. Note that currently the name of the |
| 62 | * installed library file must be exactly `lib$name.so`. |
| 63 | * @property[includesPerAbi] Set to true if a different set of headers should be |
| 64 | * exposed per-ABI. Not currently implemented. |
| 65 | * @property[dependencies] A list of other modules required by this module, in |
| 66 | * the format described by https://google.github.io/prefab/. |
| 67 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 68 | data class Module( |
| 69 | val name: String, |
| 70 | val includesPerAbi: Boolean = false, |
| 71 | val dependencies: List<String> = emptyList() |
| 72 | ) |
| 73 | |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 74 | /** |
| 75 | * The base class for all ports. |
| 76 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 77 | abstract class Port { |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 78 | /** |
| 79 | * The name of the port. Will be used as the package name in prefab.json. |
| 80 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 81 | abstract val name: String |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 82 | |
| 83 | /** |
| 84 | * The version of the package. |
| 85 | * |
| 86 | * Used as the default for [prefabVersion] and [mavenVersion] when |
| 87 | * appropriate. |
| 88 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 89 | abstract val version: String |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 90 | |
| 91 | /** |
| 92 | * The version to encode in the prefab.json. |
| 93 | * |
| 94 | * This version must be compatible with CMake's `find_package` for |
| 95 | * config-style packages. This means that it must be one to four decimal |
| 96 | * separated integers. No other format is allowed. |
| 97 | * |
| 98 | * If not set, the default is [version] as interpreted by |
| 99 | * [CMakeCompatibleVersion.parse]. |
| 100 | * |
| 101 | * For example, OpenSSL 1.1.1g will set this value to |
| 102 | * `CMakeCompatibleVersion(1, 1, 1, 7)`. |
| 103 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 104 | open val prefabVersion: CMakeCompatibleVersion |
| 105 | get() = CMakeCompatibleVersion.parse(version) |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 106 | |
| 107 | /** |
| 108 | * The version to use for the maven package. |
| 109 | * |
| 110 | * This field allows versioning the maven package differently from the |
| 111 | * package itself, which is sometimes necessary given CMake's strict version |
| 112 | * format requirements. |
| 113 | * |
| 114 | * If not set, the default is [version]. |
| 115 | * |
| 116 | * For example, this could be set to `"$name-$version-alpha-1"` to |
| 117 | * distribute an alpha of the package. |
| 118 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 119 | open val mavenVersion: String |
| 120 | get() = version |
| 121 | |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 122 | /** |
| 123 | * The relative path to the license file of this package. |
| 124 | * |
| 125 | * This file will be packaged in the AAR in the META-INF directory. |
| 126 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 127 | open val licensePath: String = "LICENSE" |
| 128 | |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 129 | /** |
| 130 | * A description of the license (name and URL) for use in the pom.xml. |
| 131 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 132 | abstract val license: License |
| 133 | |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 134 | /** |
| 135 | * A list of dependencies for this package. |
| 136 | * |
| 137 | * For example, curl depends on `listOf("openssl")`. |
| 138 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 139 | open val dependencies: List<String> = emptyList() |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 140 | |
| 141 | /** |
| 142 | * A list of modules exported by this package. |
| 143 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 144 | abstract val modules: List<Module> |
| 145 | |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 146 | /** |
| 147 | * The number of CPUs available for building. |
| 148 | * |
| 149 | * May be passed to the build system if required. |
| 150 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 151 | protected val ncpus = Runtime.getRuntime().availableProcessors() |
| 152 | |
| 153 | fun run( |
| 154 | toolchain: Toolchain, |
| 155 | sourceDirectory: File, |
| 156 | buildDirectory: File, |
| 157 | installDirectory: File, |
| 158 | workingDirectory: File |
| 159 | ): Result<Unit, String> { |
| 160 | configure( |
| 161 | toolchain, |
| 162 | sourceDirectory, |
| 163 | buildDirectory, |
| 164 | installDirectory, |
| 165 | workingDirectory |
| 166 | ).onFailure { return Result.Error(it) } |
| 167 | |
| 168 | build(toolchain, buildDirectory).onFailure { return Result.Error(it) } |
| 169 | |
| 170 | install( |
| 171 | toolchain, |
| 172 | buildDirectory, |
| 173 | installDirectory |
| 174 | ).onFailure { return Result.Error(it) } |
| 175 | |
| 176 | return Result.Ok(Unit) |
| 177 | } |
| 178 | |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 179 | /** |
| 180 | * Overridable build step for extracting the source package. |
| 181 | * |
| 182 | * @param[sourceTarball] The path to the source tarball. |
| 183 | * @param[sourceDirectory] The destination directory for the extracted |
| 184 | * source. |
| 185 | * @param[workingDirectory] The working top-level directory for this |
| 186 | * package. |
| 187 | * @return A [Result<Unit, String>][Result] describing the result of the |
| 188 | * operation. On failure, [Result.Error<String>][Result.Error] containing an |
| 189 | * error message is returned. |
| 190 | */ |
Dan Albert | abf50c1 | 2020-02-03 15:51:15 -0800 | [diff] [blame] | 191 | open fun extractSource( |
| 192 | sourceTarball: File, |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 193 | sourceDirectory: File, |
| 194 | workingDirectory: File |
| 195 | ): Result<Unit, String> { |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 196 | sourceDirectory.mkdirs() |
| 197 | return executeProcessStep( |
| 198 | listOf( |
| 199 | "tar", |
| 200 | "xf", |
Dan Albert | abf50c1 | 2020-02-03 15:51:15 -0800 | [diff] [blame] | 201 | sourceTarball.absolutePath, |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 202 | "--strip-components=1" |
| 203 | ), sourceDirectory |
| 204 | ) |
| 205 | } |
| 206 | |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 207 | /** |
| 208 | * Overridable build step for configuring the build. |
| 209 | * |
| 210 | * Any pre-build steps should be run here. |
| 211 | * |
| 212 | * In an autoconf build, this runs `configure`. |
| 213 | * |
| 214 | * @param[toolchain] The toolchain used for this build. |
| 215 | * @param[sourceDirectory] The directory containing the extracted package |
| 216 | * source. |
| 217 | * @param[buildDirectory] The directory to use for building. |
| 218 | * @param[installDirectory] The destination directory for this package's |
| 219 | * installed headers and libraries. |
| 220 | * @param[workingDirectory] The top-level working directory for this |
| 221 | * package. |
| 222 | * @return A [Result<Unit, String>][Result] describing the result of the |
| 223 | * operation. On failure, [Result.Error<String>][Result.Error] containing an |
| 224 | * error message is returned. |
| 225 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 226 | open fun configure( |
| 227 | toolchain: Toolchain, |
| 228 | sourceDirectory: File, |
| 229 | buildDirectory: File, |
| 230 | installDirectory: File, |
| 231 | workingDirectory: File |
| 232 | ): Result<Unit, String> = Result.Ok(Unit) |
| 233 | |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 234 | /** |
| 235 | * Overridable build step for building the package. |
| 236 | * |
| 237 | * In an autoconf build, this runs `make`. |
| 238 | * |
| 239 | * @param[toolchain] The toolchain used for this build. |
| 240 | * @param[buildDirectory] The directory to use for building. |
| 241 | * @return A [Result<Unit, String>][Result] describing the result of the |
| 242 | * operation. On failure, [Result.Error<String>][Result.Error] containing an |
| 243 | * error message is returned. |
| 244 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 245 | open fun build( |
| 246 | toolchain: Toolchain, |
| 247 | buildDirectory: File |
| 248 | ): Result<Unit, String> = Result.Ok(Unit) |
| 249 | |
Dan Albert | a3fd28e | 2020-05-19 16:11:16 -0700 | [diff] [blame] | 250 | /** |
| 251 | * Overridable build step for installing built artifacts for packaging. |
| 252 | * |
| 253 | * The install step is expected to install headers and libraries to the |
| 254 | * [installDirectory] with the following layout: |
| 255 | * |
| 256 | * [installDirectory] |
| 257 | * include/ |
| 258 | * <package headers> |
| 259 | * lib/ |
| 260 | * <package libraries> |
| 261 | * |
| 262 | * A matching `lib${module.name}.so` must be present in the `lib` directory |
| 263 | * for every item in [modules]. |
| 264 | * |
| 265 | * Note that it is expected for all modules to use the same headers. This is |
| 266 | * currently the case for all ports currently maintained, but could change |
| 267 | * in the future. |
| 268 | * |
| 269 | * In an autoconf build, this runs `make install`. |
| 270 | * |
| 271 | * @param[toolchain] The toolchain used for this build. |
| 272 | * @param[buildDirectory] The directory containing build artifacts. |
| 273 | * @param[installDirectory] The destination directory for this package's |
| 274 | * installed headers and libraries. |
| 275 | * @return A [Result<Unit, String>][Result] describing the result of the |
| 276 | * operation. On failure, [Result.Error<String>][Result.Error] containing an |
| 277 | * error message is returned. |
| 278 | */ |
Dan Albert | dca0d72 | 2019-07-16 14:03:43 -0700 | [diff] [blame] | 279 | open fun install( |
| 280 | toolchain: Toolchain, |
| 281 | buildDirectory: File, |
| 282 | installDirectory: File |
| 283 | ): Result<Unit, String> = Result.Ok(Unit) |
| 284 | } |