Skip to content

Commit

Permalink
[SkipCI] Deliver per ABI headers properly
Browse files Browse the repository at this point in the history
  • Loading branch information
ViliusSutkus89 committed Nov 9, 2023
1 parent 2fac102 commit df0b0ed
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 145 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ Libraries built with different NDK versions should not be used in the same appli

Run unit tests provided by upstream packages.

Figure out proper way to deliver per ABI headers.

## Ports

#### [GNU FriBidi](https://github.com/fribidi/fribidi)
Expand Down
84 changes: 0 additions & 84 deletions buildSrc/src/main/kotlin/com/android/ndkports/PortTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -125,93 +125,9 @@ abstract class PortTask(objects: ObjectFactory) : DefaultTask() {
installDirectory = installDirectoryFor(abi),
generatedDirectoryFor(abi)
)
migrateConfigFiles(abi)
}
}

private fun migrateConfigFiles(abi: Abi) {
val installDirectory = installDirectoryFor(abi)
val generatedDirectory = generatedDirectoryFor(abi)

val srcDir = installDirectory.resolve("lib")
val dstDir = installDirectory.resolve("include/android.${abi.abiName}/lib").apply { mkdirs() }

val ndkPathAbsolute = ndkPath.asFile.get().absolutePath

listOf(
srcDir.resolve("cmake"),
srcDir.resolve("pkgconfig")
).forEach { dir ->
dir.walkTopDown().forEach {
val dst = dstDir.resolve(it.relativeTo(srcDir))
if (it.isDirectory) {
dst.mkdir()
} else if (it.isFile && it.extension in listOf("cmake", "pc")) {
dst.writeText(
it.readText()
.replace(installDirectory.absolutePath, "/__PREFAB__PACKAGE__PATH__")
.replace(generatedDirectory.absolutePath, "/__PREFAB__PACKAGE__PATH__")
.replace(ndkPathAbsolute, "/__NDK__PATH__")
)
}

// Some dependencies link against static libraries,
// but don't pick up private dependencies
if (libraryType.get() == LibraryType.Static && it.isFile && it.extension == "pc") {
val sb = StringBuilder()
val libs = mutableListOf<String>()
val libsPrivate = mutableListOf<String>()
val requires = mutableListOf<String>()
val requiresPrivate = mutableListOf<String>()
dst.readLines().forEach { line ->
if (line.startsWith(prefix = "Libs:", ignoreCase = true)) {
libs.add(line.substring("Libs:".length))
}
else if (line.startsWith(prefix = "Libs.private:", ignoreCase = true)) {
libsPrivate.add(line.substring("Libs.private:".length))
}
else if (line.startsWith(prefix = "Requires:", ignoreCase = true)) {
requires.add(line.substring("Requires:".length))
}
else if (line.startsWith(prefix = "Requires.private:", ignoreCase = true)) {
requiresPrivate.add(line.substring("Requires.private:".length))
}
else {
sb.appendLine(line)
}
}
(libs + libsPrivate).joinToString(" ").trim().let { libsWithPrivates ->
if (libsWithPrivates.isNotEmpty()) {
sb.appendLine("Libs: $libsWithPrivates")
}
}
(requires + requiresPrivate).joinToString(" ").trim().let { requiresWithPrivates ->
if (requiresWithPrivates.isNotEmpty()) {
sb.appendLine("Requires: $requiresWithPrivates")
}
}
dst.writeText(sb.toString())
}
}
}

(srcDir.listFiles { file -> file.extension == "la" } ?: arrayOf<File>()).forEach {
dstDir.resolve(it.relativeTo(srcDir)).writeText(
it.readText()
.replace(installDirectory.absolutePath, "/__PREFAB__PACKAGE__PATH__")
.replace(generatedDirectory.absolutePath, "/__PREFAB__PACKAGE__PATH__")
.replace(ndkPathAbsolute, "/__NDK__PATH__")
)
}

// Remove empty dirs
installDirectory.resolve("include/android.${abi.abiName}").walkBottomUp()
.filter { it.isDirectory && it.listFiles().isNullOrEmpty() }
.forEach {
it.delete()
}
}

abstract fun buildForAbi(
toolchain: Toolchain,
portDirectory: File,
Expand Down
139 changes: 103 additions & 36 deletions buildSrc/src/main/kotlin/com/android/ndkports/PrefabPackageBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ data class ModuleDescription(
class PrefabPackageBuilder(
private val packageData: PackageData,
private val packageDirectory: File,
private val directory: File,
private val installDirectory: File,
private val sourceDirectory: File,
private val ndk: Ndk,
) {
Expand Down Expand Up @@ -106,14 +106,11 @@ class PrefabPackageBuilder(
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()
}
val dstDir = libsDir.resolve("android.${abi.abiName}")

directory.resolve("$abi/lib/$libName")
.copyTo(installDirectory.resolve(libName))
installDirectory.resolve("$abi/lib/$libName").copyTo(dstDir.resolve(libName))

installDirectory.resolve("abi.json").writeText(
dstDir.resolve("abi.json").writeText(
Json.encodeToString(
AndroidAbiMetadata(
abi = abi.abiName,
Expand Down Expand Up @@ -152,7 +149,7 @@ class PrefabPackageBuilder(
}

private fun installAssets() {
val sourceAssets = directory.parentFile.parentFile.resolve("assets")
val sourceAssets = installDirectory.parentFile.parentFile.resolve("assets")
if (sourceAssets.exists()) {
sourceAssets.copyRecursively(assetsDirectory)
}
Expand All @@ -167,38 +164,34 @@ class PrefabPackageBuilder(
}

makeModuleMetadata(module, moduleDirectory)
Abi.values().forEach { abi ->
val includeDir = directory.resolve("${abi}/include")
if (module.includesPerAbi) {
val destination = moduleDirectory.resolve("include/android.${abi.abiName}").apply { mkdir() }
val commonHeaders = includeDir.listFiles { _, name -> !Abi.values().map { "android.${it.abiName}" }.contains(name) } ?: arrayOf<File>()
val perAbiHeaders = includeDir.resolve("android.${abi.abiName}").listFiles() ?: arrayOf<File>()
(commonHeaders + perAbiHeaders).forEach {
it.copyRecursively(destination.resolve(it.name))
}
} else {
val destination = moduleDirectory.resolve("include").apply { mkdir() }
includeDir.copyRecursively(destination) { file, exception ->
if (exception !is FileAlreadyExistsException) {
throw exception
}

if (!file.readBytes().contentEquals(exception.file.readBytes())) {
val path = file.relativeTo(destination)
throw RuntimeException(
"Found duplicate headers with non-equal contents: $path"
)
}

OnErrorAction.SKIP
}
val libsDir = moduleDirectory.resolve("libs").apply { mkdir() }
for (abi in Abi.values()) {
libsDir.resolve("android.${abi.abiName}").apply { mkdir() }
installConfigForAbi(module, abi, libsDir)
if (!module.headerOnly) {
installLibForAbi(module, abi, libsDir)
}
}

if (!module.headerOnly) {
val libsDir = moduleDirectory.resolve("libs").apply { mkdirs() }
for (abi in Abi.values()) {
installLibForAbi(module, abi, libsDir)
Abi.values().forEach { abi ->
val destination = if (module.includesPerAbi) {
libsDir.resolve("android.${abi.abiName}").apply{ mkdir() }.resolve("include").apply { mkdir() }
} else {
moduleDirectory.resolve("include").apply { mkdir() }
}
installDirectory.resolve("${abi}/include").copyRecursively(destination) { file, exception ->
if (exception !is FileAlreadyExistsException) {
throw exception
}

if (!file.readBytes().contentEquals(exception.file.readBytes())) {
val path = file.relativeTo(destination)
throw RuntimeException(
"Found duplicate headers with non-equal contents: $path"
)
}
OnErrorAction.SKIP
}
}
}
Expand All @@ -209,4 +202,78 @@ class PrefabPackageBuilder(

createAndroidManifest()
}

private fun installConfigForAbi(module: ModuleDescription, abi: Abi, libsDir: File) {
val srcDir = installDirectory.resolve("$abi/lib")
val dstDir = libsDir.resolve("android.${abi.abiName}")

val abiInstallDir = installDirectory.resolve("$abi")
val generatedDir = installDirectory.resolve("../dependencies/generated/${abi.triple}").absoluteFile

listOf(
srcDir.resolve("cmake"),
srcDir.resolve("pkgconfig")
).forEach { dir ->
dir.walkTopDown().forEach {
val dst = dstDir.resolve(it.relativeTo(srcDir))
if (it.isDirectory) {
dst.mkdir()
} else if (it.isFile && it.extension in listOf("cmake", "pc")) {
dst.writeText(
it.readText()
.replace(abiInstallDir.absolutePath, "/__PREFAB__PACKAGE__PATH__")
.replace(generatedDir.absolutePath, "/__PREFAB__PACKAGE__PATH__")
.replace(ndk.path.absolutePath, "/__NDK__PATH__")
)
}

// Some dependencies link against static libraries,
// but don't pick up private dependencies
if (module.static && it.isFile && it.extension == "pc") {
val sb = StringBuilder()
val libs = mutableListOf<String>()
val libsPrivate = mutableListOf<String>()
val requires = mutableListOf<String>()
val requiresPrivate = mutableListOf<String>()
dst.readLines().forEach { line ->
if (line.startsWith(prefix = "Libs:", ignoreCase = true)) {
libs.add(line.substring("Libs:".length))
}
else if (line.startsWith(prefix = "Libs.private:", ignoreCase = true)) {
libsPrivate.add(line.substring("Libs.private:".length))
}
else if (line.startsWith(prefix = "Requires:", ignoreCase = true)) {
requires.add(line.substring("Requires:".length))
}
else if (line.startsWith(prefix = "Requires.private:", ignoreCase = true)) {
requiresPrivate.add(line.substring("Requires.private:".length))
}
else {
sb.appendLine(line)
}
}
(libs + libsPrivate).joinToString(" ").trim().let { libsWithPrivates ->
if (libsWithPrivates.isNotEmpty()) {
sb.appendLine("Libs: $libsWithPrivates")
}
}
(requires + requiresPrivate).joinToString(" ").trim().let { requiresWithPrivates ->
if (requiresWithPrivates.isNotEmpty()) {
sb.appendLine("Requires: $requiresWithPrivates")
}
}
dst.writeText(sb.toString())
}
}
}

(srcDir.listFiles { file -> file.extension == "la" } ?: arrayOf<File>()).forEach {
dstDir.resolve(it.relativeTo(srcDir)).writeText(
it.readText()
.replace(abiInstallDir.absolutePath, "/__PREFAB__PACKAGE__PATH__")
.replace(generatedDir.absolutePath, "/__PREFAB__PACKAGE__PATH__")
.replace(ndk.path.absolutePath, "/__NDK__PATH__")
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class PrefabSysrootPlugin(
val includeDir = installDir.resolve("include").apply { mkdir() }
val libDir = installDir.resolve("lib")

installHeaders(module.includePath.toFile(), includeDir, requirement.targetTriple)
migrateLibFiles(includeDir, libDir)
installHeaders(module, includeDir, requirement.targetTriple)
installConfigFiles(module, libDir, requirement.targetTriple)

if (!module.isHeaderOnly) {
module.getLibraryFor(requirement).path.toFile().apply {
Expand All @@ -51,10 +51,9 @@ class PrefabSysrootPlugin(
}
}

private fun installHeaders(src: File, includeDir: File, abiTriple: String) {
val commonHeaders = src.listFiles { _, name -> !Abi.values().map { "android.${it.abiName}" }.contains(name) } ?: arrayOf<File>()
val perAbiHeaders = src.resolve("android.${targetTripleToAbiName(abiTriple)}").listFiles() ?: arrayOf<File>()

private fun installHeaders(module: Module, includeDir: File, abiTriple: String) {
val commonHeaders = module.includePath.toFile().listFiles() ?: arrayOf<File>()
val perAbiHeaders = module.path.toFile().resolve("libs/android.${abiTriple}/include").listFiles() ?: arrayOf<File>()
(commonHeaders + perAbiHeaders).forEach {
it.copyRecursively(includeDir.resolve(it.name)) { file, exception ->
if (exception !is FileAlreadyExistsException) {
Expand All @@ -73,24 +72,25 @@ class PrefabSysrootPlugin(
}
}

private fun migrateLibFiles(includeDir: File, libDir: File) {
includeDir.resolve("lib").let {
if (it.exists()) {
it.copyRecursively(libDir) { file, exception ->
if (exception !is FileAlreadyExistsException) {
throw exception
}

if (!file.readBytes().contentEquals(exception.file.readBytes())) {
val path = file.relativeTo(includeDir)
throw RuntimeException(
"Found duplicate headers with non-equal contents: $path"
)
}

OnErrorAction.SKIP
private fun installConfigFiles(module: Module, libDir: File, abiTriple: String) {
val src = module.path.toFile().resolve("libs/android.${targetTripleToAbiName(abiTriple)}")

src.listFiles { file, filename ->
listOf("cmake", "pkgconfig").contains(filename) || file.extension == "la"
}?.forEach {
it.copyRecursively(libDir.resolve(it.name)) { file, exception ->
if (exception !is FileAlreadyExistsException) {
throw exception
}

if (!file.readBytes().contentEquals(exception.file.readBytes())) {
val path = file.relativeTo(src)
throw RuntimeException(
"Found duplicate headers with non-equal contents: $path"
)
}
it.deleteRecursively()

OnErrorAction.SKIP
}
}
}
Expand Down

0 comments on commit df0b0ed

Please sign in to comment.