{"id":20755925,"url":"https://github.com/henryquan/kotlin-cpp","last_synced_at":"2026-04-11T21:12:12.036Z","repository":{"id":177819932,"uuid":"657997521","full_name":"HenryQuan/kotlin-cpp","owner":"HenryQuan","description":"Try out Kotlin Native for future projects","archived":false,"fork":false,"pushed_at":"2023-07-01T10:46:22.000Z","size":21,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-18T04:28:42.677Z","etag":null,"topics":["cpp","kotlin-native"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HenryQuan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-24T12:55:35.000Z","updated_at":"2023-07-01T10:41:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"2f928271-ffd7-4a59-8b62-a4ce190a9af8","html_url":"https://github.com/HenryQuan/kotlin-cpp","commit_stats":null,"previous_names":["henryquan/kotlin-cpp"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HenryQuan%2Fkotlin-cpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HenryQuan%2Fkotlin-cpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HenryQuan%2Fkotlin-cpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HenryQuan%2Fkotlin-cpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HenryQuan","download_url":"https://codeload.github.com/HenryQuan/kotlin-cpp/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243061949,"owners_count":20230088,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","kotlin-native"],"created_at":"2024-11-17T09:28:00.899Z","updated_at":"2025-10-20T05:38:42.635Z","avatar_url":"https://github.com/HenryQuan.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kotlin C\n\nExperiment with Kotlin/Native to export functions from Kotlin to C++ on Windows.\n\n## Findings\n\n- `build.gradle.kts` can be challenging to setup, but much better than CMake\n- Both static and dynamic libraries can be generated with `staticLib` or `sharedLib`\n- `pthread` and `bcrypt` are required to be linked with the static library\n- Only the dynamic library works in the Windows Sandbox (a fresh environment)\n  - The static library build will fail to run due to missing DLLs\n\n## The generated header\n\nThe generated header contains everything from Kotlin. First, you can create a reference to all the symbols, mathop is the name of the library.\n\n```c++\nconst auto lib = mathop_symbols();\n```\n\nThen, you can call the function by using its kotlin package name, it can be a bit long.\n\n```c++\nauto service = lib-\u003ekotlin.root.model.service.APIService.APIService();\nlib-\u003ekotlin.root.model.service.APIService.getData(service, (void*)callback_block);\n```\n\nIn C/C++, you can define some macros to make it shorter.\n\n```c++\n#define KN lib-\u003ekotlin.root\n#define KN_MODEL KN.model\n#define KN_SERVICE KN_MODEL.service\n#define KN_API_SERVICE KN_SERVICE.APIService\n```\n\nNow, the code above can be written as:\n\n```c++\nauto service = KN_API_SERVICE.APIService();\nKN_API_SERVICE.getData(service, (void*)callback_block);\n```\n\n### Callbacks\n\nIn Kotlin, we have `suspend` functions to make asynchronous calls. In C/C++, we can use callbacks to achieve similar results. However, it can be challenging to setup both sides. First, we need to define a callback function in C/C++.\n\n```c++\nvoid callback_block(const char*);\nvoid location_block(mathop_kref_model_Location);\n```\n\nIt is nice that kotlin exports many symbols for us to use so primitive types can be used directly, but for classes from kotlin, we need to use `xxx_kref_xxx` symbols as a pointer. It isn't possible for C/C++ to know how to handle a Kotlin class, but Kotlin can. In Kotlin, we need to define callbacks we need to use in C/C++.\n\n```kotlin\n// This maps to `void callback_block(const char*);`\ntypealias StringCallback = CPointer\u003cCFunction\u003c(CValues\u003cByteVar\u003e) -\u003e Unit\u003e\u003e\n// This maps to `void location_block(mathop_kref_model_Location);`\ntypealias LocationCallback = CPointer\u003cCFunction\u003c(COpaquePointer) -\u003e Unit\u003e\u003e\n```\n\nNote that I used `COpaquePointer`. I guess it is similar to `void*` in C/C++. `mathop_kref_model_Location` must be used to prevent any crashes from C/C++. They must match exactly. Now, we can use the callbacks in Kotlin.\n\n```kotlin\nfun getData(callback: StringCallback) {\n    CoroutineScope(Dispatchers.Default).launch {\n        val data = getData()                        // Get the data suspend\n        callback.invoke(data.cstr)                  // Call `callback_block` in C/C++\n    }\n}\n\nfun traverse_locations(locationCallback: LocationCallback) {\n    for (loc in locations) {\n        val stableRef = StableRef.create(loc)       // Create a stable reference to `loc` must match with C/C++\n        val locPointer = stableRef.asCPointer()     // Create a pointer to `loc`\n        locationCallback(locPointer)                // Call `location_block` in C/C++\n        stableRef.dispose()                         // Free the memory\n    }\n}\n```\n\nIt is always easier to callback a primitive type. Now, we have the `Location` object in C/C++. We can call our lib to get the data from it.\n\n```c++\nvoid callback_block(const char* result) {\n    printf(\"callback is %s\\n\", result);\n}\n\nvoid location_block(mathop_kref_model_Location loc) {\n    printf(\"location is %s\\n\", KN_MODEL.Location.get_name(loc));\n}\n```\n\nNote that we only need to do this because it is native. For Android development, all kotlin codes are native to JVM. For iOS development, it has much better support for Swift and Objective-C. `suspend` functions are converted to `@escaping` closures. You can also access everything within your kotlin class.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenryquan%2Fkotlin-cpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhenryquan%2Fkotlin-cpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenryquan%2Fkotlin-cpp/lists"}