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 com.github.ajalt.clikt.core.CliktCommand
20 import com.github.ajalt.clikt.parameters.arguments.argument
21 import com.github.ajalt.clikt.parameters.arguments.multiple
22 import com.github.ajalt.clikt.parameters.arguments.validate
23 import com.github.ajalt.clikt.parameters.options.convert
24 import com.github.ajalt.clikt.parameters.options.default
25 import com.github.ajalt.clikt.parameters.options.flag
26 import com.github.ajalt.clikt.parameters.options.option
27 import com.github.ajalt.clikt.parameters.options.required
28 import com.github.ajalt.clikt.parameters.types.file
29 import de.swirtz.ktsrunner.objectloader.KtsObjectLoader
30 import java.io.File
31 import java.io.FileNotFoundException
32 import java.lang.RuntimeException
33 import kotlin.system.exitProcess
34 
35 class Cli : CliktCommand(help = "ndkports") {
36     private val outDir: File by option(
37         "-o",
38         "--out",
39         help = "Build directory."
40     ).file().default(File("out"))
41 
42     private val publishToMavenLocal: Boolean by option(
43         help = "Publish AARs to the local Maven repository (~/.m2/repository)"
44     ).flag()
45 
46     private val packages: List<String> by argument(
47         help = "Names of packages to build."
<lambda>null48     ).multiple().validate {
49         require(it.isNotEmpty()) { "must provide at least one package" }
50     }
51 
<lambda>null52     private val ndk: Ndk by option().convert { Ndk(File(it)) }.required()
53 
loadPortnull54     private fun loadPort(name: String): Port {
55         val portDir = File("ports").resolve(name).also {
56             if (!it.exists()) {
57                 throw FileNotFoundException("Could not find ${it.path}")
58             }
59         }
60 
61         val portFile = portDir.resolve("port.kts").also {
62             if (!it.exists()) {
63                 throw FileNotFoundException("Could not find ${it.path}")
64             }
65         }
66 
67         return KtsObjectLoader().load(portFile.reader())
68     }
69 
runnull70     override fun run() {
71         println("Building packages: ${packages.joinToString(", ")}")
72         val portsByName = packages.map { loadPort(it) }.associateBy { it.name }
73         for (port in portsByName.values) {
74             val workingDirectory =
75                 outDir.resolve(port.name).also { it.mkdirs() }
76             val sourceDirectory = workingDirectory.resolve("src")
77 
78             port.fetchSource(sourceDirectory, workingDirectory).onFailure {
79                 println(it)
80                 exitProcess(1)
81             }
82 
83             val apiForAbi = mapOf(
84                 Abi.Arm to 16,
85                 Abi.Arm64 to 21,
86                 Abi.X86 to 16,
87                 Abi.X86_64 to 21
88             )
89             for (abi in Abi.values()) {
90                 val api = apiForAbi.getOrElse(abi) {
91                     throw RuntimeException(
92                         "No API level specified for ${abi.abiName}"
93                     )
94                 }
95                 val toolchain = Toolchain(ndk, abi, api)
96 
97                 val buildDirectory = workingDirectory.resolve("build/$abi")
98                 val installDirectory = installDirectoryForPort(
99                     port.name, workingDirectory, toolchain
100                 )
101 
102                 port.run(
103                     toolchain,
104                     sourceDirectory,
105                     buildDirectory,
106                     installDirectory,
107                     workingDirectory
108                 ).onFailure {
109                     println(it)
110                     exitProcess(1)
111                 }
112             }
113 
114             PrefabPackageBuilder(
115                 port,
116                 workingDirectory,
117                 sourceDirectory,
118                 publishToMavenLocal,
119                 ndk,
120                 apiForAbi,
121                 portsByName
122             ).build()
123         }
124     }
125 }
126 
mainnull127 fun main(args: Array<String>) {
128     Cli().main(args)
129 }