blob: 2e0433f0c75a00a145072830ffaee3d105a1fa10 [file] [log] [blame]
/*
* 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)
}