1313 * See the License for the specific language governing permissions and
1414 * limitations under the License.
1515 **/
16+ import co.touchlab.cklib.gradle.CKlibGradleExtension
17+ import co.touchlab.cklib.gradle.CompileToBitcode
18+ import co.touchlab.cklib.gradle.CompileToBitcodeExtension
19+ import org.gradle.accessors.dm.LibrariesForLibs
20+ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
21+ import org.jetbrains.kotlin.konan.target.Family
22+ import org.jetbrains.kotlin.konan.target.HostManager
23+ import org.jetbrains.kotlin.konan.target.KonanTarget
24+ import org.jetbrains.kotlin.konan.target.TargetSupportException
25+ import org.jetbrains.kotlin.konan.util.ArchiveType
26+ import org.jetbrains.kotlin.konan.util.DependencyProcessor
27+ import org.jetbrains.kotlin.konan.util.DependencySource
28+
1629plugins {
1730 id(" configuration" )
1831}
1932
2033kmpConfiguration {
2134 configureShared(java9ModuleName = " org.kotlincrypto.random" , publish = true ) {
2235 common {
36+ pluginIds(libs.plugins.cklib.get().pluginId)
37+
2338 sourceSetMain {
2439 dependencies {
2540 api(libs.kotlincrypto.error)
@@ -30,11 +45,7 @@ kmpConfiguration {
3045 kotlin {
3146 with (sourceSets) {
3247 val linuxMain = findByName(" linuxMain" )
33- val androidNativeMain = findByName(" androidNativeMain" )?.apply {
34- dependencies {
35- implementation(project(" :library:internal-cinterop" ))
36- }
37- }
48+ val androidNativeMain = findByName(" androidNativeMain" )
3849
3950 if (linuxMain != null || androidNativeMain != null ) {
4051 val linuxAndroidMain = maybeCreate(" linuxAndroidMain" ).apply {
@@ -52,5 +63,121 @@ kmpConfiguration {
5263 }
5364 }
5465 }
66+
67+ kotlin {
68+ val cInteropDir = projectDir
69+ .resolve(" src" )
70+ .resolve(" nativeInterop" )
71+ .resolve(" cinterop" )
72+
73+ val interopTaskInfo = targets.filterIsInstance<KotlinNativeTarget >().map { target ->
74+ if (target.konanTarget.family == Family .ANDROID ) {
75+ target.compilations[" main" ].cinterops.create(" crypto_rand_sys" ) {
76+ definitionFile.set(cInteropDir.resolve(" $name .def" ))
77+ includeDirs(cInteropDir)
78+ }
79+ }
80+
81+ target.compilations[" test" ].cinterops.create(" syscall" ) {
82+ definitionFile.set(cInteropDir.resolve(" $name .def" ))
83+ }.interopProcessingTaskName to target.konanTarget
84+ }
85+
86+ project.extensions.configure<CompileToBitcodeExtension >(" cklib" ) {
87+ config.configure(libs)
88+
89+ create(" crypto_rand_sys" ) {
90+ language = CompileToBitcode .Language .C
91+ srcDirs = project.files(cInteropDir)
92+ includeFiles = listOf (" $compileName .c" )
93+
94+ listOf (
95+ " -Wno-unused-command-line-argument" ,
96+ ).let { compilerArgs.addAll(it) }
97+
98+ val kt = KonanTarget .predefinedTargets[target]!!
99+
100+ // Must add dependency on the test cinterop task to ensure
101+ // that Kotlin/Native dependencies get downloaded beforehand
102+ interopTaskInfo.forEach { (interopTaskName, konanTarget) ->
103+ if (kt != konanTarget) return @forEach
104+ this .dependsOn(interopTaskName)
105+ }
106+ }
107+ }
108+ }
55109 }
56110}
111+
112+ // CKLib uses too old of a version of LLVM for current version of Kotlin which produces errors for android
113+ // native due to unsupported link arguments. Below is a supplemental implementation to download and use
114+ // the -dev llvm compiler for the current kotlin version.
115+ //
116+ // The following info can be found in ~/.konan/kotlin-native-prebuild-{os}-{arch}-{kotlin version}/konan/konan.properties
117+ private object LLVM {
118+ const val URL : String = " https://download.jetbrains.com/kotlin/native/resources/llvm"
119+ const val VERSION : String = " 16.0.0"
120+
121+ // llvm-{llvm version}-{arch}-{host}-dev-{id}
122+ object DevID {
123+ object Linux {
124+ const val x86_64: Int = 80
125+ }
126+ object MacOS {
127+ const val aarch64: Int = 63
128+ const val x86_64: Int = 50
129+ }
130+ object MinGW {
131+ const val x86_64: Int = 56
132+ }
133+ }
134+ }
135+
136+ private fun CKlibGradleExtension.configure (libs : LibrariesForLibs ) {
137+ kotlinVersion = libs.versions.gradle.kotlin.get()
138+ check(kotlinVersion == " 2.1.10" ) {
139+ " Kotlin version out of date! Download URLs for LLVM need to be updated for ${project.path} "
140+ }
141+
142+ val host = HostManager .simpleOsName()
143+ val arch = HostManager .hostArch()
144+ val (id, archive) = when (host) {
145+ " linux" -> when (arch) {
146+ " x86_64" -> LLVM .DevID .Linux .x86_64 to ArchiveType .TAR_GZ
147+ else -> null
148+ }
149+ " macos" -> when (arch) {
150+ " aarch64" -> LLVM .DevID .MacOS .aarch64 to ArchiveType .TAR_GZ
151+ " x86_64" -> LLVM .DevID .MacOS .x86_64 to ArchiveType .TAR_GZ
152+ else -> null
153+ }
154+ " windows" -> when (arch) {
155+ " x86_64" -> LLVM .DevID .MinGW .x86_64 to ArchiveType .ZIP
156+ else -> null
157+ }
158+ else -> null
159+ } ? : throw TargetSupportException (" Unsupported host[$host ] or arch[$arch ]" )
160+
161+ val llvmDev = " llvm-${LLVM .VERSION } -${arch} -${host} -dev-${id} "
162+ val cklibDir = File (System .getProperty(" user.home" )).resolve(" .cklib" )
163+ llvmHome = cklibDir.resolve(llvmDev).path
164+
165+ val source = DependencySource .Remote .Public (subDirectory = " ${LLVM .VERSION } -${arch} -${host} " )
166+
167+ DependencyProcessor (
168+ dependenciesRoot = cklibDir,
169+ dependenciesUrl = LLVM .URL ,
170+ dependencyToCandidates = mapOf (llvmDev to listOf (source)),
171+ homeDependencyCache = cklibDir.resolve(" cache" ),
172+ customProgressCallback = { _, currentBytes, totalBytes ->
173+ val total = totalBytes.toString()
174+ var current = currentBytes.toString()
175+ while (current.length < 15 && current.length < total.length) {
176+ current = " $current "
177+ }
178+
179+ println (" Downloading[$llvmDev ] - $current / $total " )
180+ },
181+ archiveType = archive,
182+ ).run ()
183+ }
0 commit comments