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
19 import java.io.File
20
21 @Suppress("unused")
executeProcessStepnull22 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
installDirectoryForPortnull46 fun installDirectoryForPort(
47 name: String,
48 workingDirectory: File,
49 toolchain: Toolchain
50 ): File = workingDirectory.parentFile.resolve("$name/install/${toolchain.abi}")
51
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 */
68 data class Module(
69 val name: String,
70 val includesPerAbi: Boolean = false,
71 val dependencies: List<String> = emptyList()
72 )
73
74 /**
75 * The base class for all ports.
76 */
77 abstract class Port {
78 /**
79 * The name of the port. Will be used as the package name in prefab.json.
80 */
81 abstract val name: String
82
83 /**
84 * The version of the package.
85 *
86 * Used as the default for [prefabVersion] and [mavenVersion] when
87 * appropriate.
88 */
89 abstract val version: String
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 */
104 open val prefabVersion: CMakeCompatibleVersion
105 get() = CMakeCompatibleVersion.parse(version)
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 */
119 open val mavenVersion: String
120 get() = version
121
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 */
127 open val licensePath: String = "LICENSE"
128
129 /**
130 * A description of the license (name and URL) for use in the pom.xml.
131 */
132 abstract val license: License
133
134 /**
135 * A list of dependencies for this package.
136 *
137 * For example, curl depends on `listOf("openssl")`.
138 */
139 open val dependencies: List<String> = emptyList()
140
141 /**
142 * A list of modules exported by this package.
143 */
144 abstract val modules: List<Module>
145
146 /**
147 * The number of CPUs available for building.
148 *
149 * May be passed to the build system if required.
150 */
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
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 */
191 open fun extractSource(
192 sourceTarball: File,
193 sourceDirectory: File,
194 workingDirectory: File
195 ): Result<Unit, String> {
196 sourceDirectory.mkdirs()
197 return executeProcessStep(
198 listOf(
199 "tar",
200 "xf",
201 sourceTarball.absolutePath,
202 "--strip-components=1"
203 ), sourceDirectory
204 )
205 }
206
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 */
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
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 */
245 open fun build(
246 toolchain: Toolchain,
247 buildDirectory: File
248 ): Result<Unit, String> = Result.Ok(Unit)
249
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 */
279 open fun install(
280 toolchain: Toolchain,
281 buildDirectory: File,
282 installDirectory: File
283 ): Result<Unit, String> = Result.Ok(Unit)
284 }