• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }