diff --git a/kotlin-native/COCOAPODS.md b/kotlin-native/COCOAPODS.md index a6356a2081f..761f7ad561a 100644 --- a/kotlin-native/COCOAPODS.md +++ b/kotlin-native/COCOAPODS.md @@ -1,751 +1,3 @@ # CocoaPods integration -Kotlin/Native provides integration with the [CocoaPods dependency manager](https://cocoapods.org/). -You can add dependencies on Pod libraries as well as use a multiplatform project with -native targets as a CocoaPods dependency (Kotlin Pod). - -You can manage Pod dependencies directly in IntelliJ IDEA and enjoy all the additional features such as code highlighting -and completion. You can build the whole Kotlin project with Gradle and not ever have to switch to Xcode. - -Use Xcode only when you need to write Swift/Objective-C code or run your application on a simulator or device. -To work correctly with Xcode, you should [update your Podfile](#update-podfile-for-xcode). - -Depending on your project and purposes, you can add dependencies between [a Kotlin project and a Pod library](#add-dependencies-on-pod-libraries) as well as [a Kotlin Pod and an Xcode project](#use-a-kotlin-gradle-project-as-a-cocoapods-dependency). - ->You can also add dependencies between a Kotlin Pod and multiple Xcode projects. However, in this case you need to add a ->dependency by calling `pod install` manually for each Xcode project. In other cases, it's done automatically. -{:.note} - -## Install the CocoaPods dependency manager and plugin - -1. Install the [CocoaPods dependency manager](https://cocoapods.org/). - -
- - ```ruby - $ sudo gem install cocoapods - ``` - -
- -2. Install the [`cocoapods-generate`](https://github.com/square/cocoapods-generate) plugin. - -
- - ```ruby - $ sudo gem install cocoapods-generate - ``` - -
- -3. In `build.gradle.kts` (or `build.gradle`) of your IDEA project, apply the CocoaPods plugin as well as the Kotlin - Multiplatform plugin. - -
- - ```kotlin - plugins { - kotlin("multiplatform") version "{{ site.data.releases.latest.version }}" - kotlin("native.cocoapods") version "{{ site.data.releases.latest.version }}" - } - ``` - -
- -4. Configure `summary`, `homepage`, and `frameworkName`of the `Podspec` file in the `cocoapods` block. -`version` is a version of the Gradle project. - -
- - ```kotlin - plugins { - kotlin("multiplatform") version "{{ site.data.releases.latest.version }}" - kotlin("native.cocoapods") version "{{ site.data.releases.latest.version }}" - } - - // CocoaPods requires the podspec to have a version. - version = "1.0" - - kotlin { - cocoapods { - // Configure fields required by CocoaPods. - summary = "Some description for a Kotlin/Native module" - homepage = "Link to a Kotlin/Native module homepage" - - // You can change the name of the produced framework. - // By default, it is the name of the Gradle project. - frameworkName = "my_framework" - } - } - ``` - -
- -5. Re-import the project. - -6. Generate the [Gradle wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html) to avoid compatibility issues during an Xcode build. - -When applied, the CocoaPods plugin does the following: - -* Adds both `debug` and `release` frameworks as output binaries for all macOS, iOS, tvOS, and watchOS targets. -* Creates a `podspec` task which generates a [Podspec](https://guides.cocoapods.org/syntax/podspec.html) -file for the project. - -The `Podspec` file includes a path to an output framework and script phases that automate building this framework during -the build process of an Xcode project. - -## Add dependencies on Pod libraries - -To add dependencies between a Kotlin project and a Pod library, you should [complete the initial configuration](#install-the-cocoapods-dependency-manager-and-plugin). -This allows you to add dependencies on the following types of Pod libraries: - * [A Pod library from the CocoaPods repository](#add-a-dependency-on-a-pod-library-from-the-cocoapods-repository) - * [A Pod library stored locally](#add-a-dependency-on-a-pod-library-stored-locally) - * [A Pod library from a Git repository](#add-a-dependency-on-a-pod-library-from-the-git-repository) - * [A Pod library from an archive](#add-a-dependency-on-a-pod-library-from-an-archive) - * [A Pod library from a custom Podspec repository](#add-a-dependency-on-a-pod-library-from-a-custom-podspec-repository) - * [A Pod library with custom cinterop options](#add-a-dependency-on-a-pod-library-with-custom-cinterop-options) - * [A static Pod library](#add-a-dependency-on-a-static-pod-library) - -A Kotlin project requires the `pod()` function call in `build.gradle.kts` (`build.gradle`) for adding a Pod dependency. Each dependency requires its own separate function call. -You can specify the parameters for the dependency in the configuration block of the function. - -When you add a new dependency and re-import the project in IntelliJ IDEA, the new dependency will be added automatically. -No additional steps are required. - -To use your Kotlin project with Xcode, you should [make changes in your project Podfile](#update-podfile-for-xcode). - -### Add a dependency on a Pod library from the CocoaPods repository - -You can add dependencies on a Pod library from the CocoaPods repository with `pod()` to `build.gradle.kts` -(`build.gradle`) of your project: - -1. Specify the name of a Pod library in the `pod()` function. In the configuration block you can specify the version of the library using the `version` parameter. To use the latest version of the library, you can just omit this parameter all-together. - - > You can add dependencies on subspecs. - {:.note} - -2. Specify the minimum deployment target version for the Pod library. - - > If you don't specify the minimum deployment target version and a dependency Pod requires a higher deployment target, you will get an error. - {:.note} - -
- - ```kotlin - kotlin { - ios() - - cocoapods { - - ios.deploymentTarget = "13.5" - - summary = "CocoaPods test library" - homepage = "https://github.com/JetBrains/kotlin" - - pod("AFNetworking") { - version = "~> 4.0.1" - } - } - } - ``` - -
- -3. Re-import the project. - -To use these dependencies from the Kotlin code, import the packages `cocoapods.`. - -
- -```kotlin -import cocoapods.AFNetworking.* -``` - -
- -You can find a sample project [here](https://github.com/Kotlin/kotlin-with-cocoapods-sample). - -### Add a dependency on a Pod library stored locally - -You can add a dependency on a Pod library stored locally with `pod()` to `build.gradle.kts` (`build.gradle`) of your project: - -1. Specify the name of a Pod library in the `pod()` function. In the configuration block specify the path to the local Pod library: use the `path()` function in the `source` parameter value. - - > You can add local dependencies on subspecs as well. - > The `cocoapods` block can include dependencies to Pods stored locally and Pods from the CocoaPods repository at - > the same time. - {:.note} - -2. Specify the minimum deployment target version for the Pod library. - - > If you don't specify the minimum deployment target version and a dependency Pod requires a higher deployment target, you will get an error. - {:.note} - -
- - ```kotlin - kotlin { - ios() - - cocoapods { - summary = "CocoaPods test library" - homepage = "https://github.com/JetBrains/kotlin" - - ios.deploymentTarget = "13.5" - - pod("pod_dependency") { - version = "1.0" - source = path(project.file("../pod_dependency/pod_dependency.podspec")) - } - pod("subspec_dependency/Core") { - version = "1.0" - source = path(project.file("../subspec_dependency/subspec_dependency.podspec")) - } - pod("AFNetworking") { - version = "~> 4.0.1" - } - } - } - ``` - -
- - > You can also specify the version of the library using `version` parameter in the configuration block. - > To use the latest version of the library, omit the parameter. - {:.note} - -3. Re-import the project. - -To use these dependencies from the Kotlin code, import the packages `cocoapods.`. - -
- -```kotlin -import cocoapods.pod_dependency.* -import cocoapods.subspec_dependency.* -import cocoapods.AFNetworking.* -``` - -
- -You can find a sample project [here](https://github.com/Kotlin/kotlin-with-cocoapods-sample). - -### Add a dependency on a Pod library from the Git repository - -You can add dependencies on a Pod library from a custom Git repository with `pod()` to `build.gradle.kts` -(`build.gradle`) of your project: - -1. Specify the name of a Pod library in the `pod()` function. -In the configuration block specify the path to the git repository: use the `git()` function in the `source` parameter value. - - Additionally, you can specify the following parameters in the block after `git()`: - * `commit` – to use a specific commit from the repository - * `tag` – to use a specific tag from the repository - * `branch` – to use a specific branch from the repository - - The `git()` function prioritizes passed parameters in the following order: `commit`, `tag`, `branch`. - If you don't specify a parameter, the Kotlin plugin uses `HEAD` from the `master` branch. - - > You can combine `branch`, `commit`, and `tag` parameters to get the specific version of a Pod. - {:.note} - -2. Specify the minimum deployment target version for the Pod library. - - > If you don't specify the minimum deployment target version and a dependency Pod requires a higher deployment target, you will get an error. - {:.note} - -
- - ```kotlin - kotlin { - ios() - - cocoapods { - summary = "CocoaPods test library" - homepage = "https://github.com/JetBrains/kotlin" - - ios.deploymentTarget = "13.5" - - pod("AFNetworking") { - source = git("https://github.com/AFNetworking/AFNetworking") { - tag = "4.0.0" - } - } - - pod("JSONModel") { - source = git("https://github.com/jsonmodel/jsonmodel.git") { - branch = "key-mapper-class" - } - } - - pod("CocoaLumberjack") { - source = git("https://github.com/CocoaLumberjack/CocoaLumberjack.git") { - commit = "3e7f595e3a459c39b917aacf9856cd2a48c4dbf3" - } - } - } - } - ``` - -
- - -3. Re-import the project. - -> To work correctly with Xcode, you should specify the path to the Podspec in your Podfile. -> For example: -> ->
-> -> ```ruby -> target 'ios-app' do -> # ... other pod depedencies ... -> pod 'JSONModel', :path => '../cocoapods/kotlin-with-cocoapods-sample/kotlin-library/build/cocoapods/externalSources/git/JSONModel' -> end -> ``` -> ->
-> -{:.note} - -To use these dependencies from the Kotlin code, import the packages `cocoapods.`. - -
- -```kotlin -import cocoapods.AFNetworking.* -import cocoapods.JSONModel.* -import cocoapods.CocoaLumberjack.* -``` - -
- -You can find a sample project [here](https://github.com/Kotlin/kotlin-with-cocoapods-sample). - -### Add a dependency on a Pod library from an archive - -You can add dependencies on a Pod library from `zip`, `tar`, or `jar` archive with `pod()` to `build.gradle.kts` -(`build.gradle`) of your project: - -1. Specify the name of a Pod library in the `pod()` function. -In the configuration block specify the path to the archive: use the `url()` function with an arbitrary HTTP address in the `source` parameter value. - - Additionally, you can specify the boolean `flatten` parameter as a second argument for the `url()` function. - This parameter indicates that all the Pod files are located in the root directory of the archive. - -2. Specify the minimum deployment target version for the Pod library. - - > If you don't specify the minimum deployment target version and a dependency Pod requires a higher deployment target, you will get an error. - {:.note} - -
- - ```kotlin - kotlin { - ios() - - cocoapods { - summary = "CocoaPods test library" - homepage = "https://github.com/JetBrains/kotlin" - - ios.deploymentTarget = "13.5" - - pod("pod_dependency") { - source = url("https://github.com/Kotlin/kotlin-with-cocoapods-sample/raw/cocoapods-zip/cocoapodSourcesZip.zip", flatten = true) - } - - } - } - ``` - -
- -3. Re-import the project. - -> To work correctly with Xcode, you should specify the path to the Podspec in your Podfile. -> For example: -> ->
-> -> ```ruby -> target 'ios-app' do -> # ... other pod depedencies ... -> pod 'podspecWithFilesExample', :path => '../cocoapods/kotlin-with-cocoapods-sample/pod_dependency' -> end -> ``` -> ->
-> -{:.note} - -To use these dependencies from the Kotlin code, import the packages `cocoapods.`. - -
- -```kotlin -import cocoapods.pod_dependency.* -``` - -
- -You can find a sample project [here](https://github.com/Kotlin/kotlin-with-cocoapods-sample). - -### Add a dependency on a Pod library from a custom Podspec repository - -You can add dependencies on a Pod library from a custom Podspec repository with `pod()` and `specRepos` to `build.gradle.kts` -(`build.gradle`) of your project: - -1. Specify the HTTP address to the custom Podspec repository using the `url()` inside the `specRepos` block. - -2. Specify the name of a Pod library in the `pod()` function. - -3. Specify the minimum deployment target version for the Pod library. - - > If you don't specify the minimum deployment target version and a dependency Pod requires a higher deployment target, you will get an error. - {:.note} - -
- - ```kotlin - kotlin { - ios() - - cocoapods { - summary = "CocoaPods test library" - homepage = "https://github.com/JetBrains/kotlin" - - ios.deploymentTarget = "13.5" - - specRepos { - url("https://github.com/Kotlin/kotlin-cocoapods-spec.git") - } - pod("example") - - } - } - ``` - -
- -4. Re-import the project. - -> To work correctly with Xcode, you should specify the location of specs at the beginning of your Podfile. -> For example: -> ->
-> -> ```ruby -> source 'https://github.com/Kotlin/kotlin-cocoapods-spec.git' -> ``` -> ->
-> -> You should also specify the path to the Podspec in your Podfile. -> For example: -> ->
-> -> ```ruby -> target 'ios-app' do -> # ... other pod depedencies ... -> pod 'podspecWithFilesExample', :path => '../cocoapods/kotlin-with-cocoapods-sample/pod_dependency' -> end -> ``` -> ->
-> -{:.note} - -To use these dependencies from the Kotlin code, import the packages `cocoapods.`. - -
- -```kotlin -import cocoapods.example.* -``` - -
- -You can find a sample project [here](https://github.com/Kotlin/kotlin-with-cocoapods-sample). - -### Add a dependency on a Pod library with custom cinterop options - -You can add dependencies on a Pod library with custom cinterop options with `pod()` to `build.gradle.kts` -(`build.gradle`) of your project: - -1. Specify the name of a Pod library in the `pod()` function. -In the configuration block specify the cinterop options: - - * `extraOpts` – to specify the list of options for a Pod library. For example, specific flags: `extraOpts = listOf("-compiler-option")` - * `packageName` – to specify the package name. If you specify this, you can import the library using the package name: `import `. - -2. Specify the minimum deployment target version for the Pod library. - - > If you don't specify the minimum deployment target version and a dependency Pod requires a higher deployment target, you will get an error. - {:.note} - -
- - ```kotlin - kotlin { - ios() - - cocoapods { - summary = "CocoaPods test library" - homepage = "https://github.com/JetBrains/kotlin" - - ios.deploymentTarget = "13.5" - - useLibraries() - - pod("YandexMapKit") { - packageName = "YandexMK" - } - - } - } - ``` - -
- -3. Re-import the project. - -To use these dependencies from the Kotlin code, import the packages `cocoapods.`. - -
- -```kotlin -import cocoapods.YandexMapKit.* -``` - -
- -If you use the `packageName` parameter, you can import the library using the package name: `import `: - -
- -```kotlin -import YandexMK.YMKPoint -import YandexMK.YMKDistance -``` - -
- -### Add a dependency on a static Pod library - -You can add dependencies on a static Pod library with `pod()` and `useLibraries()` to `build.gradle.kts` -(`build.gradle`) of your project: - -1. Specify the name of the library using the `pod()` function. - -2. Call the `useLibraries()` function: it enables a special flag for static libraries. - -3. Specify the minimum deployment target version for the Pod library. - - > If you don't specify the minimum deployment target version and a dependency Pod requires a higher deployment target, you will get an error. - {:.note} - -
- - ```kotlin - kotlin { - ios() - - cocoapods { - summary = "CocoaPods test library" - homepage = "https://github.com/JetBrains/kotlin" - - ios.deploymentTarget = "13.5" - - pod("YandexMapKit") { - version = "~> 3.2" - } - useLibraries() - - } - } - ``` - -
- - -4. Re-import the project. - -To use these dependencies from the Kotlin code, import the packages `cocoapods.`. - -
- -```kotlin -import cocoapods.YandexMapKit.* -``` - -
- -### Update Podfile for Xcode - -If you want to import your Kotlin project in an Xcode project, you’ll need to make some changes to your Podfile for it to work correctly: - -* If your project has any Git, HTTP, or custom Podspec repository dependencies, you should also specify the path to the Podspec in the Podfile. - - For example, if you add a dependency on `podspecWithFilesExample`, declare the path to the Podspec in the Podfile: - -
- - ```ruby - target 'ios-app' do - # ... other depedencies ... - pod 'podspecWithFilesExample', :path => 'cocoapods/externalSources/url/podspecWithFilesExample' - end - ``` - -
- - The `:path` should contain the filepath to the Pod. - -* When you add a library from the custom Podspec repository, you should also specify the [location](https://guides.cocoapods.org/syntax/podfile.html#source) of specs at the beginning of your Podfile: - -
- - ```ruby - source 'https://github.com/Kotlin/kotlin-cocoapods-spec.git' - - target 'kotlin-cocoapods-xcproj' do - # ... other depedencies ... - pod 'example' - end - ``` - -
- -> Re-import the project after making changes in Podfile. -{:.note} - -If you don't make these changes to the Podfile, the `podInstall` task will fail and the CocoaPods plugin will show an error message in the log. - -Check out the `withXcproject` branch of the [sample project](https://github.com/Kotlin/kotlin-with-cocoapods-sample), which contains an example of Xcode integration with an existing Xcode project named `kotlin-cocoapods-xcproj`. - -## Use a Kotlin Gradle project as a CocoaPods dependency - -You can use a Kotlin Multiplatform project with native targets as a CocoaPods dependency (Kotlin Pod). You can include such a dependency -in the Podfile of the Xcode project by its name and path to the project directory containing the generated Podspec. -This dependency will be automatically built (and rebuilt) along with this project. -Such an approach simplifies importing to Xcode by removing a need to write the corresponding Gradle tasks and Xcode build steps manually. - -You can add dependencies between: -* [A Kotlin Pod and an Xcode project with one target](#add-a-dependency-between-a-kotlin-pod-and-xcode-project-with-one-target) -* [A Kotlin Pod and an Xcode project with several targets](#add-a-dependency-between-a-kotlin-pod-with-an-xcode-project-with-several-targets) - -> To correctly import the dependencies into the Kotlin/Native module, the -`Podfile` must contain either [`use_modular_headers!`](https://guides.cocoapods.org/syntax/podfile.html#use_modular_headers_bang) -or [`use_frameworks!`](https://guides.cocoapods.org/syntax/podfile.html#use_frameworks_bang) -directive. -{:.note} - -### Add a dependency between a Kotlin Pod and Xcode project with one target - -1. Create an Xcode project with a `Podfile` if you haven’t done so yet. -2. Add the path to your Xcode project `Podfile` with `podfile = project.file(..)` to `build.gradle.kts` (`build.gradle`) -of your Kotlin project. - This step helps synchronize your Xcode project with Kotlin Pod dependencies by calling `pod install` for your `Podfile`. -3. Specify the minimum deployment target version for the Pod library. - > If you don't specify the minimum deployment target version and a dependency Pod requires a higher deployment target, you will get an error. - {:.note} - -
- - ```kotlin - kotlin { - ios() - - cocoapods { - summary = "CocoaPods test library" - homepage = "https://github.com/JetBrains/kotlin" - ios.deploymentTarget = "13.5" - pod("AFNetworking") { - version = "~> 4.0.0" - } - podfile = project.file("../ios-app/Podfile") - } - } - ``` - -
- -4. Add the name and path of the Kotlin Pod you want to include in the Xcode project to `Podfile`. - -
- - ```ruby - use_frameworks! - - platform :ios, '13.5' - - target 'ios-app' do - pod 'kotlin_library', :path => '../kotlin-library' - end - ``` - -
- -5. Re-import the project. - -### Add a dependency between a Kotlin Pod with an Xcode project with several targets - -1. Create an Xcode project with a `Podfile` if you haven’t done so yet. -2. Add the path to your Xcode project `Podfile` with `podfile = project.file(..)` to `build.gradle.kts` (`build.gradle`) of - your Kotlin project. - This step helps synchronize your Xcode project with Kotlin Pod dependencies by calling `pod install` for your `Podfile`. -3. Add dependencies to the Pod libraries that you want to use in your project with `pod()`. -4. For each target, specify the minimum deployment target version for the Pod library. - > If you don't specify the minimum deployment target version and a dependency Pod requires a higher deployment target, you will get an error. - {:.note} - -
- - ```kotlin - kotlin { - ios() - tvos() - - cocoapods { - summary = "CocoaPods test library" - homepage = "https://github.com/JetBrains/kotlin" - ios.deploymentTarget = "13.5" - tvos.deploymentTarget = "13.4" - - pod("AFNetworking") { - version = "~> 4.0.0" - } - podfile = project.file("../severalTargetsXcodeProject/Podfile") // specify the path to Podfile - } - } - ``` - -
- -5. Add the name and path of the Kotlin Pod you want to include in the Xcode project to the `Podfile`. - -
- - ```ruby - target 'iosApp' do - use_frameworks! - platform :ios, '13.5' - # Pods for iosApp - pod 'kotlin_library', :path => '../kotlin-library' - end - - target 'TVosApp' do - use_frameworks! - platform :tvos, '13.4' - - # Pods for TVosApp - pod 'kotlin_library', :path => '../kotlin-library' - end - ``` - -
- -6. Re-import the project. - -You can find a sample project [here](https://github.com/Kotlin/multitarget-xcode-with-kotlin-cocoapods-sample). +The content of this page is moved to https://kotlinlang.org/docs/native-cocoapods.html \ No newline at end of file diff --git a/kotlin-native/CONCURRENCY.md b/kotlin-native/CONCURRENCY.md index 21b340cb9fb..565f2160999 100644 --- a/kotlin-native/CONCURRENCY.md +++ b/kotlin-native/CONCURRENCY.md @@ -1,222 +1,3 @@ ## Concurrency in Kotlin/Native - Kotlin/Native runtime doesn't encourage a classical thread-oriented concurrency - model with mutually exclusive code blocks and conditional variables, as this model is - known to be error-prone and unreliable. Instead, we suggest a collection of - alternative approaches, allowing you to use hardware concurrency and implement blocking IO. - Those approaches are as follows, and they will be elaborated on in further sections: - * Workers with message passing - * Object subgraph ownership transfer - * Object subgraph freezing - * Object subgraph detachment - * Raw shared memory using C globals - * Atomic primitives and references - * Coroutines for blocking operations (not covered in this document) - -### Workers - - Instead of threads Kotlin/Native runtime offers the concept of workers: concurrently executed - control flow streams with an associated request queue. Workers are very similar to the actors - in the Actor Model. A worker can exchange Kotlin objects with another worker, so that at any moment - each mutable object is owned by a single worker, but ownership can be transferred. - See section [Object transfer and freezing](#transfer). - - Once a worker is started with the `Worker.start` function call, it can be addressed with its own unique integer - worker id. Other workers, or non-worker concurrency primitives, such as OS threads, can send a message - to the worker with the `execute` call. - -
- - ```kotlin -val future = execute(TransferMode.SAFE, { SomeDataForWorker() }) { - // data returned by the second function argument comes to the - // worker routine as 'input' parameter. - input -> - // Here we create an instance to be returned when someone consumes result future. - WorkerResult(input.stringParam + " result") -} - -future.consume { - // Here we see result returned from routine above. Note that future object or - // id could be transferred to another worker, so we don't have to consume future - // in same execution context it was obtained. - result -> println("result is $result") -} -``` - -
- - The call to `execute` uses a function passed as its second parameter to produce an object subgraph - (i.e. set of mutually referring objects) which is then passed as a whole to that worker, it is then no longer - available to the thread that initiated the request. This property is checked if the first parameter - is `TransferMode.SAFE` by graph traversal and is just assumed to be true, if it is `TransferMode.UNSAFE`. - The last parameter to `execute` is a special Kotlin lambda, which is not allowed to capture any state, - and is actually invoked in the target worker's context. Once processed, the result is transferred to whatever consumes - it in the future, and it is attached to the object graph of that worker/thread. - - If an object is transferred in `UNSAFE` mode and is still accessible from multiple concurrent executors, - program will likely crash unexpectedly, so consider that last resort in optimizing, not a general purpose - mechanism. - - For a more complete example please refer to the [workers example](https://github.com/JetBrains/kotlin-native/tree/master/samples/workers) - in the Kotlin/Native repository. - - -### Object transfer and freezing - - An important invariant that Kotlin/Native runtime maintains is that the object is either owned by a single - thread/worker, or it is immutable (_shared XOR mutable_). This ensures that the same data has a single mutator, - and so there is no need for locking to exist. To achieve such an invariant, we use the concept of not externally - referred object subgraphs. - This is a subgraph which has no external references from outside of the subgraph, which could be checked - algorithmically with O(N) complexity (in ARC systems), where N is the number of elements in such a subgraph. - Such subgraphs are usually produced as a result of a lambda expression, for example some builder, and may not - contain objects, referred to externally. - - Freezing is a runtime operation making a given object subgraph immutable, by modifying the object header - so that future mutation attempts throw an `InvalidMutabilityException`. It is deep, so - if an object has a pointer to other objects - transitive closure of such objects will be frozen. - Freezing is a one way transformation, frozen objects cannot be unfrozen. Frozen objects have a nice - property that due to their immutability, they can be freely shared between multiple workers/threads - without breaking the "mutable XOR shared" invariant. - - If an object is frozen it can be checked with an extension property `isFrozen`, and if it is, object sharing - is allowed. Currently, Kotlin/Native runtime only freezes the enum objects after creation, although additional - autofreezing of certain provably immutable objects could be implemented in the future. - - -### Object subgraph detachment - - An object subgraph without external references can be disconnected using `DetachedObjectGraph` to - a `COpaquePointer` value, which could be stored in `void*` data, so the disconnected object subgraphs - can be stored in a C data structure, and later attached back with `DetachedObjectGraph.attach()` in an arbitrary thread - or a worker. Combining it with [raw memory sharing](#shared) it allows side channel object transfer between - concurrent threads, if the worker mechanisms are insufficient for a particular task. Note, that object detachment - may require explicit leaving function holding object references and then performing cyclic garbage collection. - For example, code like: - -
- -```kotlin -val graph = DetachedObjectGraph { - val map = mutableMapOf() - for (entry in map.entries) { - // ... - } - map -} -``` - -
- - will not work as expected and will throw runtime exception, as there are uncollected cycles in the detached graph, while: - -
- -```kotlin -val graph = DetachedObjectGraph { - { - val map = mutableMapOf() - for (entry in map.entries) { - // ... - } - map - }().also { - kotlin.native.internal.GC.collect() - } - } -``` - -
- - will work properly, as holding references will be released, and then cyclic garbage affecting reference counter is - collected. - - -### Raw shared memory - - Considering the strong ties between Kotlin/Native and C via interoperability, in conjunction with the other mechanisms - mentioned above it is possible to build popular data structures, like concurrent hashmap or shared cache with - Kotlin/Native. It is possible to rely upon shared C data, and store in it references to detached object subgraphs. - Consider the following .def file: - -
- -```c -package = global - ---- -typedef struct { - int version; - void* kotlinObject; -} SharedData; - -SharedData sharedData; -``` - -
- -After running the cinterop tool it can share Kotlin data in a versionized global structure, -and interact with it from Kotlin transparently via autogenerated Kotlin like this: - -
- -```kotlin -class SharedData(rawPtr: NativePtr) : CStructVar(rawPtr) { - var version: Int - var kotlinObject: COpaquePointer? -} -``` - -
- -So in combination with the top level variable declared above, it can allow looking at the same memory from different -threads and building traditional concurrent structures with platform-specific synchronization primitives. - - -### Global variables and singletons - - Frequently, global variables are a source of unintended concurrency issues, so _Kotlin/Native_ implements -the following mechanisms to prevent the unintended sharing of state via global objects: - - * global variables, unless specially marked, can be only accessed from the main thread (that is, the thread - _Kotlin/Native_ runtime was first initialized), if other thread access such a global, `IncorrectDereferenceException` is thrown - * for global variables marked with the `@kotlin.native.ThreadLocal` annotation each threads keeps thread-local copy, - so changes are not visible between threads - * for global variables marked with the `@kotlin.native.SharedImmutable` annotation value is shared, but frozen - before publishing, so each threads sees the same value - * singleton objects unless marked with `@kotlin.native.ThreadLocal` are frozen and shared, lazy values allowed, - unless cyclic frozen structures were attempted to be created - * enums are always frozen - - Combined, these mechanisms allow natural race-free programming with code reuse across platforms in MPP projects. - - -### Atomic primitives and references - - Kotlin/Native standard library provides primitives for safe working with concurrently mutable data, namely -`AtomicInt`, `AtomicLong`, `AtomicNativePtr`, `AtomicReference` and `FreezableAtomicReference` in the package -`kotlin.native.concurrent`. -Atomic primitives allows concurrency-safe update operations, such as increment, decrement and compare-and-swap, -along with value setters and getters. Atomic primitives are considered always frozen by the runtime, and -while their fields can be updated with the regular `field.value += 1`, it is not concurrency safe. -Value must be be changed using dedicated operations, so it is possible to perform concurrent-safe -global counters and similar data structures. - - Some algorithms require shared mutable references across the multiple workers, for example global mutable -configuration could be implemented as an immutable instance of properties list atomically replaced with the -new version on configuration update as the whole in a single transaction. This way no inconsistent configuration -could be seen, and at the same time configuration could be updated as needed. -To achieve such functionality Kotlin/Native runtime provides two related classes: -`kotlin.native.concurrent.AtomicReference` and `kotlin.native.concurrent.FreezableAtomicReference`. -Atomic reference holds reference to a frozen or immutable object, and its value could be updated by set -or compare-and-swap operation. Thus, dedicated set of objects could be used to create mutable shared object graphs -(of immutable objects). Cycles in the shared memory could be created using atomic references. -Kotlin/Native runtime doesn't support garbage collecting cyclic data when reference cycle goes through -`AtomicReference` or frozen `FreezableAtomicReference`. So to avoid memory leaks atomic references -that are potentially parts of shared cyclic data should be zeroed out once no longer needed. - - If atomic reference value is attempted to be set to non-frozen value runtime exception is thrown. - - Freezable atomic reference is similar to the regular atomic reference, but until frozen behaves like regular box -for a reference. After freezing it behaves like an atomic reference, and can only hold a reference to a frozen object. \ No newline at end of file +The content of this page is moved to https://kotlinlang.org/docs/native-concurrency.html \ No newline at end of file diff --git a/kotlin-native/DEBUGGING.md b/kotlin-native/DEBUGGING.md index 6f66bc8db96..e05c00d7bfe 100644 --- a/kotlin-native/DEBUGGING.md +++ b/kotlin-native/DEBUGGING.md @@ -1,263 +1,3 @@ ## Debugging -Currently the Kotlin/Native compiler produces debug info compatible with the DWARF 2 specification, so modern debugger tools can -perform the following operations: -- breakpoints -- stepping -- inspection of type information -- variable inspection - -### Producing binaries with debug info with Kotlin/Native compiler - -To produce binaries with the Kotlin/Native compiler it's sufficient to use the ``-g`` option on the command line.
-_Example:_ - -
- -```bash -0:b-debugger-fixes:minamoto@unit-703(0)# cat - > hello.kt -fun main(args: Array) { - println("Hello world") - println("I need your clothes, your boots and your motocycle") -} -0:b-debugger-fixes:minamoto@unit-703(0)# dist/bin/konanc -g hello.kt -o terminator -KtFile: hello.kt -0:b-debugger-fixes:minamoto@unit-703(0)# lldb terminator.kexe -(lldb) target create "terminator.kexe" -Current executable set to 'terminator.kexe' (x86_64). -(lldb) b kfun:main(kotlin.Array) -Breakpoint 1: where = terminator.kexe`kfun:main(kotlin.Array) + 4 at hello.kt:2, address = 0x00000001000012e4 -(lldb) r -Process 28473 launched: '/Users/minamoto/ws/.git-trees/debugger-fixes/terminator.kexe' (x86_64) -Process 28473 stopped -* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 - frame #0: 0x00000001000012e4 terminator.kexe`kfun:main(kotlin.Array) at hello.kt:2 - 1 fun main(args: Array) { --> 2 println("Hello world") - 3 println("I need your clothes, your boots and your motocycle") - 4 } -(lldb) n -Hello world -Process 28473 stopped -* thread #1, queue = 'com.apple.main-thread', stop reason = step over - frame #0: 0x00000001000012f0 terminator.kexe`kfun:main(kotlin.Array) at hello.kt:3 - 1 fun main(args: Array) { - 2 println("Hello world") --> 3 println("I need your clothes, your boots and your motocycle") - 4 } -(lldb) -``` - -
- -### Breakpoints -Modern debuggers provide several ways to set a breakpoint, see below for a tool-by-tool breakdown: - -#### lldb -- by name - -
- -```bash -(lldb) b -n kfun:main(kotlin.Array) -Breakpoint 4: where = terminator.kexe`kfun:main(kotlin.Array) + 4 at hello.kt:2, address = 0x00000001000012e4 -``` - -
- - _``-n`` is optional, this flag is applied by default_ -- by location (filename, line number) - -
- -```bash -(lldb) b -f hello.kt -l 1 -Breakpoint 1: where = terminator.kexe`kfun:main(kotlin.Array) + 4 at hello.kt:2, address = 0x00000001000012e4 -``` - -
- -- by address - -
- -```bash -(lldb) b -a 0x00000001000012e4 -Breakpoint 2: address = 0x00000001000012e4 -``` - -
- -- by regex, you might find it useful for debugging generated artifacts, like lambda etc. (where used ``#`` symbol in name). - -
- -```bash -3: regex = 'main\(', locations = 1 - 3.1: where = terminator.kexe`kfun:main(kotlin.Array) + 4 at hello.kt:2, address = terminator.kexe[0x00000001000012e4], unresolved, hit count = 0 -``` - -
- -#### gdb -- by regex - -
- -```bash -(gdb) rbreak main( -Breakpoint 1 at 0x1000109b4 -struct ktype:kotlin.Unit &kfun:main(kotlin.Array); -``` - -
- -- by name __unusable__, because ``:`` is a separator for the breakpoint by location - -
- -```bash -(gdb) b kfun:main(kotlin.Array) -No source file named kfun. -Make breakpoint pending on future shared library load? (y or [n]) y -Breakpoint 1 (kfun:main(kotlin.Array)) pending -``` - -
- -- by location - -
- -```bash -(gdb) b hello.kt:1 -Breakpoint 2 at 0x100001704: file /Users/minamoto/ws/.git-trees/hello.kt, line 1. -``` - -
- -- by address - -
- -```bash -(gdb) b *0x100001704 -Note: breakpoint 2 also set at pc 0x100001704. -Breakpoint 3 at 0x100001704: file /Users/minamoto/ws/.git-trees/hello.kt, line 2. -``` - -
- - -### Stepping -Stepping functions works mostly the same way as for C/C++ programs - -### Variable inspection - -Variable inspections for var variables works out of the box for primitive types. -For non-primitive types there are custom pretty printers for lldb in -`konan_lldb.py`: - -
- -```bash -λ cat main.kt | nl - 1 fun main(args: Array) { - 2 var x = 1 - 3 var y = 2 - 4 var p = Point(x, y) - 5 println("p = $p") - 6 } - - 7 data class Point(val x: Int, val y: Int) - -λ lldb ./program.kexe -o 'b main.kt:5' -o -(lldb) target create "./program.kexe" -Current executable set to './program.kexe' (x86_64). -(lldb) b main.kt:5 -Breakpoint 1: where = program.kexe`kfun:main(kotlin.Array) + 289 at main.kt:5, address = 0x000000000040af11 -(lldb) r -Process 4985 stopped -* thread #1, name = 'program.kexe', stop reason = breakpoint 1.1 - frame #0: program.kexe`kfun:main(kotlin.Array) at main.kt:5 - 2 var x = 1 - 3 var y = 2 - 4 var p = Point(x, y) --> 5 println("p = $p") - 6 } - 7 - 8 data class Point(val x: Int, val y: Int) - -Process 4985 launched: './program.kexe' (x86_64) -(lldb) fr var -(int) x = 1 -(int) y = 2 -(ObjHeader *) p = 0x00000000007643d8 -(lldb) command script import dist/tools/konan_lldb.py -(lldb) fr var -(int) x = 1 -(int) y = 2 -(ObjHeader *) p = [x: ..., y: ...] -(lldb) p p -(ObjHeader *) $2 = [x: ..., y: ...] -(lldb) script lldb.frame.FindVariable("p").GetChildMemberWithName("x").Dereference().GetValue() -'1' -(lldb) -``` - -
- - -Getting representation of the object variable (var) could also be done using the -built-in runtime function `Konan_DebugPrint` (this approach also works for gdb, -using a module of command syntax): - -
- -```bash -0:b-debugger-fixes:minamoto@unit-703(0)# cat ../debugger-plugin/1.kt | nl -p - 1 fun foo(a:String, b:Int) = a + b - 2 fun one() = 1 - 3 fun main(arg:Array) { - 4 var a_variable = foo("(a_variable) one is ", 1) - 5 var b_variable = foo("(b_variable) two is ", 2) - 6 var c_variable = foo("(c_variable) two is ", 3) - 7 var d_variable = foo("(d_variable) two is ", 4) - 8 println(a_variable) - 9 println(b_variable) - 10 println(c_variable) - 11 println(d_variable) - 12 } -0:b-debugger-fixes:minamoto@unit-703(0)# lldb ./program.kexe -o 'b -f 1.kt -l 9' -o r -(lldb) target create "./program.kexe" -Current executable set to './program.kexe' (x86_64). -(lldb) b -f 1.kt -l 9 -Breakpoint 1: where = program.kexe`kfun:main(kotlin.Array) + 463 at 1.kt:9, address = 0x0000000100000dbf -(lldb) r -(a_variable) one is 1 -Process 80496 stopped -* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 - frame #0: 0x0000000100000dbf program.kexe`kfun:main(kotlin.Array) at 1.kt:9 - 6 var c_variable = foo("(c_variable) two is ", 3) - 7 var d_variable = foo("(d_variable) two is ", 4) - 8 println(a_variable) --> 9 println(b_variable) - 10 println(c_variable) - 11 println(d_variable) - 12 } - -Process 80496 launched: './program.kexe' (x86_64) -(lldb) expression -- (int32_t)Konan_DebugPrint(a_variable) -(a_variable) one is 1(int32_t) $0 = 0 -(lldb) - -``` - -
- - -### Known issues -- performance of Python bindings. - -_Note:_ Supporting the DWARF 2 specification means that the debugger tool recognizes Kotlin as C89, because before the DWARF 5 specification, there is no identifier for the Kotlin language type in specification. - +The content of this page is moved to https://kotlinlang.org/docs/native-debugging.html \ No newline at end of file diff --git a/kotlin-native/FAQ.md b/kotlin-native/FAQ.md index 37a45224f8a..5993c85b615 100644 --- a/kotlin-native/FAQ.md +++ b/kotlin-native/FAQ.md @@ -1,206 +1 @@ -### Q: How do I run my program? - -A: Define a top level function `fun main(args: Array)` or just `fun main()` if you are not interested -in passed arguments, please ensure it's not in a package. -Also compiler switch `-entry` could be used to make any function taking `Array` or no arguments -and return `Unit` as an entry point. - - -### Q: What is Kotlin/Native memory management model? - -A: Kotlin/Native provides an automated memory management scheme, similar to what Java or Swift provides. -The current implementation includes an automated reference counter with a cycle collector to collect cyclical -garbage. - - -### Q: How do I create a shared library? - -A: Use the `-produce dynamic` compiler switch, or `binaries.sharedLib()` in Gradle, i.e. - -
- -```kotlin -kotlin { - iosArm64("mylib") { - binaries.sharedLib() - } -} -``` - -
- -It will produce a platform-specific shared object (.so on Linux, .dylib on macOS, and .dll on Windows targets) and a -C language header, allowing the use of all public APIs available in your Kotlin/Native program from C/C++ code. -See `samples/python_extension` for an example of using such a shared object to provide a bridge between Python and -Kotlin/Native. - - -### Q: How do I create a static library or an object file? - -A: Use the `-produce static` compiler switch, or `binaries.staticLib()` in Gradle, i.e. - -
- -```kotlin -kotlin { - iosArm64("mylib") { - binaries.staticLib() - } -} -``` - -
- -It will produce a platform-specific static object (.a library format) and a C language header, allowing you to -use all the public APIs available in your Kotlin/Native program from C/C++ code. - - -### Q: How do I run Kotlin/Native behind a corporate proxy? - -A: As Kotlin/Native needs to download a platform specific toolchain, you need to specify -`-Dhttp.proxyHost=xxx -Dhttp.proxyPort=xxx` as the compiler's or `gradlew` arguments, -or set it via the `JAVA_OPTS` environment variable. - - -### Q: How do I specify a custom Objective-C prefix/name for my Kotlin framework? - -A: Use the `-module-name` compiler option or matching Gradle DSL statement, i.e. - -
-
- -```kotlin -kotlin { - iosArm64("myapp") { - binaries.framework { - freeCompilerArgs += listOf("-module-name", "TheName") - } - } -} -``` - -
-
- -
-
- -```groovy -kotlin { - iosArm64("myapp") { - binaries.framework { - freeCompilerArgs += ["-module-name", "TheName"] - } - } -} -``` - -
-
- -### Q: How do I rename the iOS framework? (default name is _\_.framework) - -A: Use the `baseName` option. This will also set the module name. - -
- -```kotlin -kotlin { - iosArm64("myapp") { - binaries { - framework { - baseName = "TheName" - } - } - } -} -``` - -
- -### Q: How do I enable bitcode for my Kotlin framework? - -A: By default gradle plugin adds it on iOS target. - * For debug build it embeds placeholder LLVM IR data as a marker. - * For release build it embeds bitcode as data. - -Or commandline arguments: `-Xembed-bitcode` (for release) and `-Xembed-bitcode-marker` (debug) - -Setting this in a Gradle DSL: -
- -```kotlin -kotlin { - iosArm64("myapp") { - binaries { - framework { - // Use "marker" to embed the bitcode marker (for debug builds). - // Use "disable" to disable embedding. - embedBitcode("bitcode") // for release binaries. - } - } - } -} -``` - -
- -These options have nearly the same effect as clang's `-fembed-bitcode`/`-fembed-bitcode-marker` -and swiftc's `-embed-bitcode`/`-embed-bitcode-marker`. - -### Q: Why do I see `InvalidMutabilityException`? - -A: It likely happens, because you are trying to mutate a frozen object. An object can transfer to the -frozen state either explicitly, as objects reachable from objects on which the `kotlin.native.concurrent.freeze` is called, -or implicitly (i.e. reachable from `enum` or global singleton object - see the next question). - - -### Q: How do I make a singleton object mutable? - -A: Currently, singleton objects are immutable (i.e. frozen after creation), and it's generally considered -good practise to have the global state immutable. If for some reason you need a mutable state inside such an -object, use the `@konan.ThreadLocal` annotation on the object. Also the `kotlin.native.concurrent.AtomicReference` class could be -used to store different pointers to frozen objects in a frozen object and automatically update them. - -### Q: How can I compile my project against the Kotlin/Native master? - -A: One of the following should be done: - -
- -For the CLI, you can compile using gradle as stated in the README (and if you get errors, you can try to do a ./gradlew clean): - -
- -```bash -./gradlew dependencies:update -./gradlew dist distPlatformLibs -``` - -
- - -You can then set the `KONAN_HOME` env variable to the generated `dist` folder in the git repository. - -
- -
-For Gradle, you can use Gradle composite builds like this: - -
- - -```bash -# Set with the path of your kotlin-native clone -export KONAN_REPO=$PWD/../kotlin-native - -# Run this once since it is costly, you can remove the `clean` task if not big changes were made from the last time you did this -pushd $KONAN_REPO && git pull && ./gradlew clean dependencies:update dist distPlatformLibs && popd - -# In your project, you set have to the org.jetbrains.kotlin.native.home property, and include as composite the shared and gradle-plugin builds -./gradlew check -Porg.jetbrains.kotlin.native.home=$KONAN_REPO/dist --include-build $KONAN_REPO/shared --include-build $KONAN_REPO/tools/kotlin-native-gradle-plugin -``` - -
- -
+The content of this page is moved to https://kotlinlang.org/docs/native-faq.html \ No newline at end of file diff --git a/kotlin-native/GRADLE_PLUGIN.md b/kotlin-native/GRADLE_PLUGIN.md index 38deb1bb44f..72c09a2ecbb 100644 --- a/kotlin-native/GRADLE_PLUGIN.md +++ b/kotlin-native/GRADLE_PLUGIN.md @@ -3,7 +3,7 @@ Since 1.3.40, a separate Gradle plugin for Kotlin/Native is deprecated in favor of the `kotlin-multiplatform` plugin. This plugin provides an IDE support along with support of the new multiplatform project model introduced in Kotlin 1.3.0. Below you can find a short list of differences between `kotlin-platform-native` and `kotlin-muliplatform` plugins. -For more information see the `kotlin-muliplatform` [documentation page](https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html). +For more information see the `kotlin-muliplatform` [documentation page](https://kotlinlang.org/docs/mpp-discover-project.html). For `kotlin-platform-native` reference see the [corresponding section](#kotlin-platform-native-reference). ### Applying the multiplatform plugin diff --git a/kotlin-native/IMMUTABILITY.md b/kotlin-native/IMMUTABILITY.md index 746610d084a..b20185485cb 100644 --- a/kotlin-native/IMMUTABILITY.md +++ b/kotlin-native/IMMUTABILITY.md @@ -1,31 +1,3 @@ # Immutability in Kotlin/Native - Kotlin/Native implements strict mutability checks, ensuring -the important invariant that the object is either immutable or -accessible from the single thread at that moment in time (`mutable XOR global`). - - Immutability is a runtime property in Kotlin/Native, and can be applied -to an arbitrary object subgraph using the `kotlin.native.concurrent.freeze` function. -It makes all the objects reachable from the given one immutable, -such a transition is a one-way operation (i.e., objects cannot be unfrozen later). -Some naturally immutable objects such as `kotlin.String`, `kotlin.Int`, and -other primitive types, along with `AtomicInt` and `AtomicReference` are frozen -by default. If a mutating operation is applied to a frozen object, -an `InvalidMutabilityException` is thrown. - - To achieve `mutable XOR global` invariant, all globally visible state (currently, -`object` singletons and enums) are automatically frozen. If object freezing -is not desired, a `kotlin.native.ThreadLocal` annotation can be used, which will make -the object state thread local, and so, mutable (but the changed state is not visible to -other threads). - - Top level/global variables of non-primitive types are by default accessible in the -main thread (i.e., the thread which initialized _Kotlin/Native_ runtime first) only. -Access from another thread will lead to an `IncorrectDereferenceException` being thrown. -To make such variables accessible in other threads, you can use either the `@ThreadLocal` annotation, -and mark the value thread local or `@SharedImmutable`, which will make the value frozen and accessible -from other threads. - - Class `AtomicReference` can be used to publish the changed frozen state to -other threads, and so build patterns like shared caches. - +The content of this page is moved to https://kotlinlang.org/docs/native-immutability.html \ No newline at end of file diff --git a/kotlin-native/INTEROP.md b/kotlin-native/INTEROP.md index bbcfbb84083..83c9b604420 100644 --- a/kotlin-native/INTEROP.md +++ b/kotlin-native/INTEROP.md @@ -1,722 +1,3 @@ # _Kotlin/Native_ interoperability # -## Introduction ## - - _Kotlin/Native_ follows the general tradition of Kotlin to provide excellent -existing platform software interoperability. In the case of a native platform, -the most important interoperability target is a C library. So _Kotlin/Native_ -comes with a `cinterop` tool, which can be used to quickly generate -everything needed to interact with an external library. - - The following workflow is expected when interacting with the native library. - * create a `.def` file describing what to include into bindings - * use the `cinterop` tool to produce Kotlin bindings - * run _Kotlin/Native_ compiler on an application to produce the final executable - - The interoperability tool analyses C headers and produces a "natural" mapping of -the types, functions, and constants into the Kotlin world. The generated stubs can be -imported into an IDE for the purpose of code completion and navigation. - - Interoperability with Swift/Objective-C is provided too and covered in a -separate document [OBJC_INTEROP.md](OBJC_INTEROP.md). - -## Platform libraries ## - - Note that in many cases there's no need to use custom interoperability library creation mechanisms described below, -as for APIs available on the platform standardized bindings called [platform libraries](PLATFORM_LIBS.md) -could be used. For example, POSIX on Linux/macOS platforms, Win32 on Windows platform, or Apple frameworks -on macOS/iOS are available this way. - -## Simple example ## - -Install libgit2 and prepare stubs for the git library: - -
- -```bash - -cd samples/gitchurn -../../dist/bin/cinterop -def src/nativeInterop/cinterop/libgit2.def \ - -compiler-option -I/usr/local/include -o libgit2 -``` - -
- -Compile the client: - -
- -```bash -../../dist/bin/kotlinc src/gitChurnMain/kotlin \ - -library libgit2 -o GitChurn -``` - -
- -Run the client: - -
- -```bash -./GitChurn.kexe ../.. -``` - -
- - -## Creating bindings for a new library ## - - To create bindings for a new library, start by creating a `.def` file. -Structurally it's a simple property file, which looks like this: - -
- -```c -headers = png.h -headerFilter = png.h -package = png -``` - -
- - -Then run the `cinterop` tool with something like this (note that for host libraries that are not included -in the sysroot search paths, headers may be needed): - -
- -```bash -cinterop -def png.def -compiler-option -I/usr/local/include -o png -``` - -
- - -This command will produce a `png.klib` compiled library and -`png-build/kotlin` directory containing Kotlin source code for the library. - -If the behavior for a certain platform needs to be modified, you can use a format like -`compilerOpts.osx` or `compilerOpts.linux` to provide platform-specific values -to the options. - -Note, that the generated bindings are generally platform-specific, so if you are developing for -multiple targets, the bindings need to be regenerated. - -After the generation of bindings, they can be used by the IDE as a proxy view of the -native library. - -For a typical Unix library with a config script, the `compilerOpts` will likely contain -the output of a config script with the `--cflags` flag (maybe without exact paths). - -The output of a config script with `--libs` will be passed as a `-linkedArgs` `kotlinc` -flag value (quoted) when compiling. - -### Selecting library headers - -When library headers are imported to a C program with the `#include` directive, -all of the headers included by these headers are also included in the program. -So all header dependencies are included in generated stubs as well. - -This behavior is correct but it can be very inconvenient for some libraries. So -it is possible to specify in the `.def` file which of the included headers are to -be imported. The separate declarations from other headers can also be imported -in case of direct dependencies. - -#### Filtering headers by globs - -It is possible to filter headers by globs. The `headerFilter` property value -from the `.def` file is treated as a space-separated list of globs. If the -included header matches any of the globs, then the declarations from this header -are included into the bindings. - -The globs are applied to the header paths relative to the appropriate include -path elements, e.g. `time.h` or `curl/curl.h`. So if the library is usually -included with `#include `, then it would probably be -correct to filter headers with - -
- -```c -headerFilter = SomeLibrary/** -``` - -
- -If a `headerFilter` is not specified, then all headers are included. - -#### Filtering by module maps - -Some libraries have proper `module.modulemap` or `module.map` files in its -headers. For example, macOS and iOS system libraries and frameworks do. -The [module map file](https://clang.llvm.org/docs/Modules.html#module-map-language) -describes the correspondence between header files and modules. When the module -maps are available, the headers from the modules that are not included directly -can be filtered out using the experimental `excludeDependentModules` option of the -`.def` file: - -
- -```c -headers = OpenGL/gl.h OpenGL/glu.h GLUT/glut.h -compilerOpts = -framework OpenGL -framework GLUT -excludeDependentModules = true -``` - -
- - -When both `excludeDependentModules` and `headerFilter` are used, they are -applied as an intersection. - -### C compiler and linker options ### - - Options passed to the C compiler (used to analyze headers, such as preprocessor definitions) and the linker -(used to link final executables) can be passed in the definition file as `compilerOpts` and `linkerOpts` -respectively. For example - -
- -```c -compilerOpts = -DFOO=bar -linkerOpts = -lpng -``` - -
- -Target-specific options, only applicable to the certain target can be specified as well, such as - -
- - ```c - compilerOpts = -DBAR=bar - compilerOpts.linux_x64 = -DFOO=foo1 - compilerOpts.mac_x64 = -DFOO=foo2 - ``` - -
- -and so, C headers on Linux will be analyzed with `-DBAR=bar -DFOO=foo1` and on macOS with `-DBAR=bar -DFOO=foo2`. -Note that any definition file option can have both common and the platform-specific part. - -### Adding custom declarations ### - - Sometimes it is required to add custom C declarations to the library before -generating bindings (e.g., for [macros](#macros)). Instead of creating an -additional header file with these declarations, you can include them directly -to the end of the `.def` file, after a separating line, containing only the -separator sequence `---`: - -
- -```c -headers = errno.h - ---- - -static inline int getErrno() { - return errno; -} -``` - -
- -Note that this part of the `.def` file is treated as part of the header file, so -functions with the body should be declared as `static`. -The declarations are parsed after including the files from the `headers` list. - -### Including static library in your klib - -Sometimes it is more convenient to ship a static library with your product, -rather than assume it is available within the user's environment. -To include a static library into `.klib` use `staticLibrary` and `libraryPaths` -clauses. For example: - -
- -```c -headers = foo.h -staticLibraries = libfoo.a -libraryPaths = /opt/local/lib /usr/local/opt/curl/lib -``` - -
- -When given the above snippet the `cinterop` tool will search `libfoo.a` in -`/opt/local/lib` and `/usr/local/opt/curl/lib`, and if it is found include the -library binary into `klib`. - -When using such `klib` in your program, the library is linked automatically. - -## Using bindings ## - -### Basic interop types ### - -All the supported C types have corresponding representations in Kotlin: - -* Signed, unsigned integral, and floating point types are mapped to their - Kotlin counterpart with the same width. -* Pointers and arrays are mapped to `CPointer?`. -* Enums can be mapped to either Kotlin enum or integral values, depending on - heuristics and the [definition file hints](#definition-file-hints). -* Structs / unions are mapped to types having fields available via the dot notation, - i.e. `someStructInstance.field1`. -* `typedef` are represented as `typealias`. - -Also, any C type has the Kotlin type representing the lvalue of this type, -i.e., the value located in memory rather than a simple immutable self-contained -value. Think C++ references, as a similar concept. -For structs (and `typedef`s to structs) this representation is the main one -and has the same name as the struct itself, for Kotlin enums it is named -`${type}Var`, for `CPointer` it is `CPointerVar`, and for most other -types it is `${type}Var`. - -For types that have both representations, the one with a "lvalue" has a mutable -`.value` property for accessing the value. - -#### Pointer types #### - -The type argument `T` of `CPointer` must be one of the "lvalue" types -described above, e.g., the C type `struct S*` is mapped to `CPointer`, -`int8_t*` is mapped to `CPointer`, and `char**` is mapped to -`CPointer>`. - -C null pointer is represented as Kotlin's `null`, and the pointer type -`CPointer` is not nullable, but the `CPointer?` is. The values of this -type support all the Kotlin operations related to handling `null`, e.g. `?:`, `?.`, -`!!` etc.: - -
- -```kotlin -val path = getenv("PATH")?.toKString() ?: "" -``` - -
- -Since the arrays are also mapped to `CPointer`, it supports the `[]` operator -for accessing values by index: - -
- -```kotlin -fun shift(ptr: CPointer, length: Int) { - for (index in 0 .. length - 2) { - ptr[index] = ptr[index + 1] - } -} -``` - -
- -The `.pointed` property for `CPointer` returns the lvalue of type `T`, -pointed by this pointer. The reverse operation is `.ptr`: it takes the lvalue -and returns the pointer to it. - -`void*` is mapped to `COpaquePointer` – the special pointer type which is the -supertype for any other pointer type. So if the C function takes `void*`, then -the Kotlin binding accepts any `CPointer`. - -Casting a pointer (including `COpaquePointer`) can be done with -`.reinterpret`, e.g.: - -
- -```kotlin -val intPtr = bytePtr.reinterpret() -``` - -
- -or - -
- -```kotlin -val intPtr: CPointer = bytePtr.reinterpret() -``` - -
- -As is with C, these reinterpret casts are unsafe and can potentially lead to -subtle memory problems in the application. - -Also there are unsafe casts between `CPointer?` and `Long` available, -provided by the `.toLong()` and `.toCPointer()` extension methods: - -
- -```kotlin -val longValue = ptr.toLong() -val originalPtr = longValue.toCPointer() -``` - -
- -Note that if the type of the result is known from the context, the type argument -can be omitted as usual due to the type inference. - -### Memory allocation ### - -The native memory can be allocated using the `NativePlacement` interface, e.g. - -
- -```kotlin -val byteVar = placement.alloc() -``` - -
- -or - -
- -```kotlin -val bytePtr = placement.allocArray(5) -``` - -
- -The most "natural" placement is in the object `nativeHeap`. -It corresponds to allocating native memory with `malloc` and provides an additional -`.free()` operation to free allocated memory: - -
- -```kotlin -val buffer = nativeHeap.allocArray(size) - -nativeHeap.free(buffer) -``` - -
- -However, the lifetime of allocated memory is often bound to the lexical scope. -It is possible to define such scope with `memScoped { ... }`. -Inside the braces, the temporary placement is available as an implicit receiver, -so it is possible to allocate native memory with `alloc` and `allocArray`, -and the allocated memory will be automatically freed after leaving the scope. - -For example, the C function returning values through pointer parameters can be -used like - -
- -```kotlin -val fileSize = memScoped { - val statBuf = alloc() - val error = stat("/", statBuf.ptr) - statBuf.st_size -} -``` - -
- -### Passing pointers to bindings ### - -Although C pointers are mapped to the `CPointer` type, the C function -pointer-typed parameters are mapped to `CValuesRef`. When passing -`CPointer` as the value of such a parameter, it is passed to the C function as is. -However, the sequence of values can be passed instead of a pointer. In this case -the sequence is passed "by value", i.e., the C function receives the pointer to -the temporary copy of that sequence, which is valid only until the function returns. - -The `CValuesRef` representation of pointer parameters is designed to support -C array literals without explicit native memory allocation. -To construct the immutable self-contained sequence of C values, the following -methods are provided: - -* `${type}Array.toCValues()`, where `type` is the Kotlin primitive type -* `Array?>.toCValues()`, `List?>.toCValues()` -* `cValuesOf(vararg elements: ${type})`, where `type` is a primitive or pointer - -For example: - -C: - -
- -```c -void foo(int* elements, int count); -... -int elements[] = {1, 2, 3}; -foo(elements, 3); -``` - -
- -Kotlin: - -
- -```kotlin -foo(cValuesOf(1, 2, 3), 3) -``` - -
- -### Working with the strings ### - -Unlike other pointers, the parameters of type `const char*` are represented as -a Kotlin `String`. So it is possible to pass any Kotlin string to a binding -expecting a C string. - -There are also some tools available to convert between Kotlin and C strings -manually: - -* `fun CPointer.toKString(): String` -* `val String.cstr: CValuesRef`. - - To get the pointer, `.cstr` should be allocated in native memory, e.g. - -
- - ``` - val cString = kotlinString.cstr.getPointer(nativeHeap) - ``` - -
- -In all cases, the C string is supposed to be encoded as UTF-8. - -To skip automatic conversion and ensure raw pointers are used in the bindings, a `noStringConversion` -statement in the `.def` file could be used, i.e. - -
- -```c -noStringConversion = LoadCursorA LoadCursorW -``` - -
- -This way any value of type `CPointer` can be passed as an argument of `const char*` type. -If a Kotlin string should be passed, code like this could be used: - -
- -```kotlin -memScoped { - LoadCursorA(null, "cursor.bmp".cstr.ptr) // for ASCII version - LoadCursorW(null, "cursor.bmp".wcstr.ptr) // for Unicode version -} -``` - -
- -### Scope-local pointers ### - -It is possible to create a scope-stable pointer of C representation of `CValues` -instance using the `CValues.ptr` extension property, available under `memScoped { ... }`. -It allows using the APIs which require C pointers with a lifetime bound to a certain `MemScope`. For example: - -
- -```kotlin -memScoped { - items = arrayOfNulls?>(6) - arrayOf("one", "two").forEachIndexed { index, value -> items[index] = value.cstr.ptr } - menu = new_menu("Menu".cstr.ptr, items.toCValues().ptr) - ... -} -``` - -
- -In this example, all values passed to the C API `new_menu()` have a lifetime of the innermost `memScope` -it belongs to. Once the control flow leaves the `memScoped` scope the C pointers become invalid. - -### Passing and receiving structs by value ### - -When a C function takes or returns a struct / union `T` by value, the corresponding -argument type or return type is represented as `CValue`. - -`CValue` is an opaque type, so the structure fields cannot be accessed with -the appropriate Kotlin properties. It should be possible, if an API uses structures -as handles, but if field access is required, there are the following conversion -methods available: - -* `fun T.readValue(): CValue`. Converts (the lvalue) `T` to a `CValue`. - So to construct the `CValue`, `T` can be allocated, filled, and then - converted to `CValue`. - -* `CValue.useContents(block: T.() -> R): R`. Temporarily places the - `CValue` to memory, and then runs the passed lambda with this placed - value `T` as receiver. So to read a single field, the following code can be - used: - -
- - ```kotlin - val fieldValue = structValue.useContents { field } - ``` - -
- - -### Callbacks ### - -To convert a Kotlin function to a pointer to a C function, -`staticCFunction(::kotlinFunction)` can be used. It is also able to provide -the lambda instead of a function reference. The function or lambda must not -capture any values. - -If the callback doesn't run in the main thread, it is mandatory to init the _Kotlin/Native_ -runtime by calling `kotlin.native.initRuntimeIfNeeded()`. - -#### Passing user data to callbacks #### - -Often C APIs allow passing some user data to callbacks. Such data is usually -provided by the user when configuring the callback. It is passed to some C function -(or written to the struct) as e.g. `void*`. -However, references to Kotlin objects can't be directly passed to C. -So they require wrapping before configuring the callback and then unwrapping in -the callback itself, to safely swim from Kotlin to Kotlin through the C world. -Such wrapping is possible with `StableRef` class. - -To wrap the reference: - -
- -```kotlin -val stableRef = StableRef.create(kotlinReference) -val voidPtr = stableRef.asCPointer() -``` - -
- -where the `voidPtr` is a `COpaquePointer` and can be passed to the C function. - -To unwrap the reference: - -
- -```kotlin -val stableRef = voidPtr.asStableRef() -val kotlinReference = stableRef.get() -``` - -
- -where `kotlinReference` is the original wrapped reference. - -The created `StableRef` should eventually be manually disposed using -the `.dispose()` method to prevent memory leaks: - -
- -```kotlin -stableRef.dispose() -``` - -
- -After that it becomes invalid, so `voidPtr` can't be unwrapped anymore. - -See the `samples/libcurl` for more details. - -### Macros ### - -Every C macro that expands to a constant is represented as a Kotlin property. -Other macros are not supported. However, they can be exposed manually by -wrapping them with supported declarations. E.g. function-like macro `FOO` can be -exposed as function `foo` by -[adding the custom declaration](#adding-custom-declarations) to the library: - -
- -```c -headers = library/base.h - ---- - -static inline int foo(int arg) { - return FOO(arg); -} -``` - -
- -### Definition file hints ### - -The `.def` file supports several options for adjusting the generated bindings. - -* `excludedFunctions` property value specifies a space-separated list of the names - of functions that should be ignored. This may be required because a function - declared in the C header is not generally guaranteed to be really callable, and - it is often hard or impossible to figure this out automatically. This option - can also be used to workaround a bug in the interop itself. - -* `strictEnums` and `nonStrictEnums` properties values are space-separated - lists of the enums that should be generated as a Kotlin enum or as integral - values correspondingly. If the enum is not included into any of these lists, - then it is generated according to the heuristics. - -* `noStringConversion` property value is space-separated lists of the functions whose - `const char*` parameters shall not be autoconverted as Kotlin string - -### Portability ### - - Sometimes the C libraries have function parameters or struct fields of a -platform-dependent type, e.g. `long` or `size_t`. Kotlin itself doesn't provide -neither implicit integer casts nor C-style integer casts (e.g. -`(size_t) intValue`), so to make writing portable code in such cases easier, -the `convert` method is provided: - -
- -```kotlin -fun ${type1}.convert<${type2}>(): ${type2} -``` -
- -where each of `type1` and `type2` must be an integral type, either signed or unsigned. - -`.convert<${type}>` has the same semantics as one of the -`.toByte`, `.toShort`, `.toInt`, `.toLong`, -`.toUByte`, `.toUShort`, `.toUInt` or `.toULong` -methods, depending on `type`. - -The example of using `convert`: - -
- -```kotlin -fun zeroMemory(buffer: COpaquePointer, size: Int) { - memset(buffer, 0, size.convert()) -} -``` - -
- -Also, the type parameter can be inferred automatically and so may be omitted -in some cases. - - -### Object pinning ### - - Kotlin objects could be pinned, i.e. their position in memory is guaranteed to be stable -until unpinned, and pointers to such objects inner data could be passed to the C functions. For example - -
- -```kotlin -fun readData(fd: Int): String { - val buffer = ByteArray(1024) - buffer.usePinned { pinned -> - while (true) { - val length = recv(fd, pinned.addressOf(0), buffer.size.convert(), 0).toInt() - - if (length <= 0) { - break - } - // Now `buffer` has raw data obtained from the `recv()` call. - } - } -} -``` - -
- -Here we use service function `usePinned`, which pins an object, executes block and unpins it on normal and -exception paths. +The content of this page is moved to https://kotlinlang.org/docs/native-c-interop.html \ No newline at end of file diff --git a/kotlin-native/IOS_SYMBOLICATION.md b/kotlin-native/IOS_SYMBOLICATION.md index c7d58ec0cc1..cb0153fa577 100644 --- a/kotlin-native/IOS_SYMBOLICATION.md +++ b/kotlin-native/IOS_SYMBOLICATION.md @@ -1,74 +1,3 @@ # Symbolicating iOS crash reports -Debugging an iOS application crash sometimes involves analyzing crash reports. -More info about crash reports can be found -[in the official documentation](https://developer.apple.com/library/archive/technotes/tn2151/_index.html). - -Crash reports generally require symbolication to become properly readable: -symbolication turns machine code addresses into human-readable source locations. -The document below describes some specific details of symbolicating crash reports -from iOS applications using Kotlin. - -## Producing .dSYM for release Kotlin binaries - -To symbolicate addresses in Kotlin code (e.g. for stack trace elements -corresponding to Kotlin code) `.dSYM` bundle for Kotlin code is required. - -By default Kotlin/Native compiler produces `.dSYM` for release -(i.e. optimized) binaries on Darwin platforms. This can be disabled with `-Xadd-light-debug=disable` -compiler flag. At the same time this option is disabled by default for other platforms, to enable it use `-Xadd-light-debug=enable`. -To control option in Gradle, use - -```kotlin -kotlin { - targets.withType { - binaries.all { - freeCompilerArgs += "-Xadd-light-debug={enable|disable}" - } - } -} -``` - -(in Kotlin DSL). - -In projects created from IntelliJ IDEA or AppCode templates these `.dSYM` bundles -are then discovered by Xcode automatically. - -## Make frameworks static when using rebuild from bitcode - -Rebuilding Kotlin-produced framework from bitcode invalidates the original `.dSYM`. -If it is performed locally, make sure the updated `.dSYM` is used when symbolicating -crash reports. - -If rebuilding is performed on App Store side, then `.dSYM` of rebuilt *dynamic* framework -seems discarded and not downloadable from App Store Connect. -So in this case it may be required to make the framework static, e.g. with - -```kotlin -kotlin { - targets.withType { - binaries.withType { - isStatic = true - } - } -} -``` - -(in Kotlin DSL). - -## Decode inlined stack frames - -Xcode doesn't seem to properly decode stack trace elements of inlined function -calls (these aren't only Kotlin `inline` functions but also functions that are -inlined when optimizing machine code). So some stack trace elements may be -missing. If this is the case, consider using `lldb` to process crash report -that is already symbolicated by Xcode, for example: - -```bash -$ lldb -b -o "script import lldb.macosx" -o "crashlog file.crash" -``` - -This command should output crash report that is additionally processed and -includes inlined stack trace elements. - -More details can be found in [LLDB documentation](https://lldb.llvm.org/use/symbolication.html). +The content of this page is moved to https://kotlinlang.org/docs/native-ios-symbolication.html \ No newline at end of file diff --git a/kotlin-native/LIBRARIES.md b/kotlin-native/LIBRARIES.md index 4539e6c3e0d..6438ec64616 100644 --- a/kotlin-native/LIBRARIES.md +++ b/kotlin-native/LIBRARIES.md @@ -1,245 +1,3 @@ # Kotlin/Native libraries -## Kotlin compiler specifics - -To produce a library with the Kotlin/Native compiler use the `-produce library` or `-p library` flag. For example: - -
- -```bash -$ kotlinc foo.kt -p library -o bar -``` - -
- -the above command will produce a `bar.klib` with the compiled contents of `foo.kt`. - -To link to a library use the `-library ` or `-l ` flag. For example: - -
- -```bash -$ kotlinc qux.kt -l bar -``` - -
- - -the above command will produce a `program.kexe` out of `qux.kt` and `bar.klib` - - -## cinterop tool specifics - -The **cinterop** tool produces `.klib` wrappers for native libraries as its main output. -For example, using the simple `libgit2.def` native library definition file provided in your Kotlin/Native distribution - -
- -```bash -$ cinterop -def samples/gitchurn/src/nativeInterop/cinterop/libgit2.def -compiler-option -I/usr/local/include -o libgit2 -``` - -
- -we will obtain `libgit2.klib`. - -See more details in [INTEROP.md](INTEROP.md) - - -## klib utility - -The **klib** library management utility allows you to inspect and install the libraries. - -The following commands are available. - -To list library contents: - -
- -```bash -$ klib contents -``` - -
- -To inspect the bookkeeping details of the library - -
- -```bash -$ klib info -``` - -
- -To install the library to the default location use - -
- -```bash -$ klib install -``` - -
- -To remove the library from the default repository use - -
- -```bash -$ klib remove -``` - -
- -All of the above commands accept an additional `-repository ` argument for specifying a repository different to the default one. - -
- -```bash -$ klib -repository -``` - -
- - -## Several examples - -First let's create a library. -Place the tiny library source code into `kotlinizer.kt`: - -
- -```kotlin -package kotlinizer -val String.kotlinized - get() = "Kotlin $this" -``` - -```bash -$ kotlinc kotlinizer.kt -p library -o kotlinizer -``` - -
- -The library has been created in the current directory: - -
- -```bash -$ ls kotlinizer.klib -kotlinizer.klib -``` - -
- -Now let's check out the contents of the library: - -
- -```bash -$ klib contents kotlinizer -``` - -
- -We can install `kotlinizer` to the default repository: - -
- -```bash -$ klib install kotlinizer -``` - -
- -Remove any traces of it from the current directory: - -
- -```bash -$ rm kotlinizer.klib -``` - -
- -Create a very short program and place it into a `use.kt` : - -
- -```kotlin -import kotlinizer.* - -fun main(args: Array) { - println("Hello, ${"world".kotlinized}!") -} -``` - -
- -Now compile the program linking with the library we have just created: - -
- -```bash -$ kotlinc use.kt -l kotlinizer -o kohello -``` - -
- -And run the program: - -
- -```bash -$ ./kohello.kexe -Hello, Kotlin world! -``` - -
- -Have fun! - -# Advanced topics - -## Library search sequence - -When given a `-library foo` flag, the compiler searches the `foo` library in the following order: - - * Current compilation directory or an absolute path. - - * All repositories specified with `-repo` flag. - - * Libraries installed in the default repository (For now the default is `~/.konan`, however it could be changed by setting **KONAN_DATA_DIR** environment variable). - - * Libraries installed in `$installation/klib` directory. - -## The library format - -Kotlin/Native libraries are zip files containing a predefined -directory structure, with the following layout: - -**foo.klib** when unpacked as **foo/** gives us: - -```yaml - - foo/ - - $component_name/ - - ir/ - - Serialized Kotlin IR. - - targets/ - - $platform/ - - kotlin/ - - Kotlin compiled to LLVM bitcode. - - native/ - - Bitcode files of additional native objects. - - $another_platform/ - - There can be several platform specific kotlin and native pairs. - - linkdata/ - - A set of ProtoBuf files with serialized linkage metadata. - - resources/ - - General resources such as images. (Not used yet). - - manifest - A file in *java property* format describing the library. -``` - -An example layout can be found in `klib/stdlib` directory of your installation. - +The content of this page is moved to https://kotlinlang.org/docs/native-libraries.html \ No newline at end of file diff --git a/kotlin-native/OBJC_INTEROP.md b/kotlin-native/OBJC_INTEROP.md index 6c49cd061a2..b2a071746e0 100644 --- a/kotlin-native/OBJC_INTEROP.md +++ b/kotlin-native/OBJC_INTEROP.md @@ -1,426 +1,3 @@ # _Kotlin/Native_ interoperability with Swift/Objective-C -This document covers some details of Kotlin/Native interoperability with -Swift/Objective-C. - -## Usage - -Kotlin/Native provides bidirectional interoperability with Objective-C. -Objective-C frameworks and libraries can be used in Kotlin code if -properly imported to the build (system frameworks are imported by default). -See e.g. "Using cinterop" in -[Gradle plugin documentation](GRADLE_PLUGIN.md#using-cinterop). -A Swift library can be used in Kotlin code if its API is exported to Objective-C -with `@objc`. Pure Swift modules are not yet supported. - -Kotlin modules can be used in Swift/Objective-C code if compiled into a -framework (see "Targets and output kinds" section in [Gradle plugin documentation](GRADLE_PLUGIN.md#targets-and-output-kinds)). -See [calculator sample](https://github.com/JetBrains/kotlin-native/tree/master/samples/calculator) for an example. - -## Mappings - -The table below shows how Kotlin concepts are mapped to Swift/Objective-C and vice versa. - -"->" and "<-" indicate that mapping only goes one way. - -| Kotlin | Swift | Objective-C | Notes | -| ------ | ----- |------------ | ----- | -| `class` | `class` | `@interface` | [note](#name-translation) | -| `interface` | `protocol` | `@protocol` | | -| `constructor`/`create` | Initializer | Initializer | [note](#initializers) | -| Property | Property | Property | [note](#top-level-functions-and-properties) [note](#setters)| -| Method | Method | Method | [note](#top-level-functions-and-properties) [note](#method-names-translation) | -| `suspend` -> | `completionHandler:` | | [note](#errors-and-exceptions) | -| `@Throws fun` | `throws` | `error:(NSError**)error` | [note](#errors-and-exceptions) | -| Extension | Extension | Category member | [note](#extensions-and-category-members) | -| `companion` member <- | Class method or property | Class method or property | | -| `null` | `nil` | `nil` | | -| `Singleton` | `Singleton()` | `[Singleton singleton]` | [note](#kotlin-singletons) | -| Primitive type | Primitive type / `NSNumber` | | [note](#nsnumber) | -| `Unit` return type | `Void` | `void` | | -| `String` | `String` | `NSString` | | -| `String` | `NSMutableString` | `NSMutableString` | [note](#nsmutablestring) | -| `List` | `Array` | `NSArray` | | -| `MutableList` | `NSMutableArray` | `NSMutableArray` | | -| `Set` | `Set` | `NSSet` | | -| `MutableSet` | `NSMutableSet` | `NSMutableSet` | [note](#collections) | -| `Map` | `Dictionary` | `NSDictionary` | | -| `MutableMap` | `NSMutableDictionary` | `NSMutableDictionary` | [note](#collections) | -| Function type | Function type | Block pointer type | [note](#function-types) | -| Inline classes | Unsupported| Unsupported| [note](#unsupported) | - - -### Name translation - -Objective-C classes are imported into Kotlin with their original names. -Protocols are imported as interfaces with `Protocol` name suffix, -i.e. `@protocol Foo` -> `interface FooProtocol`. -These classes and interfaces are placed into a package [specified in build configuration](#usage) -(`platform.*` packages for preconfigured system frameworks). - -The names of Kotlin classes and interfaces are prefixed when imported to Objective-C. -The prefix is derived from the framework name. - -### Initializers - -Swift/Objective-C initializers are imported to Kotlin as constructors and factory methods -named `create`. The latter happens with initializers declared in the Objective-C category or -as a Swift extension, because Kotlin has no concept of extension constructors. - -Kotlin constructors are imported as initializers to Swift/Objective-C. - -### Setters - -Writeable Objective-C properties overriding read-only properties of the superclass are represented as `setFoo()` method for the property `foo`. Same goes for a protocol's read-only properties that are implemented as mutable. - -### Top-level functions and properties - -Top-level Kotlin functions and properties are accessible as members of special classes. -Each Kotlin file is translated into such a class. E.g. - -
- -```kotlin -// MyLibraryUtils.kt -package my.library - -fun foo() {} -``` - -
- -can be called from Swift like - -
- -```swift -MyLibraryUtilsKt.foo() -``` - -
- -### Method names translation - -Generally Swift argument labels and Objective-C selector pieces are mapped to Kotlin -parameter names. Anyway these two concepts have different semantics, so sometimes -Swift/Objective-C methods can be imported with a clashing Kotlin signature. In this case -the clashing methods can be called from Kotlin using named arguments, e.g.: - -
- -```swift -[player moveTo:LEFT byMeters:17] -[player moveTo:UP byInches:42] -``` - -
- -in Kotlin it would be: - -
- -```kotlin -player.moveTo(LEFT, byMeters = 17) -player.moveTo(UP, byInches = 42) -``` - -
- -### Errors and exceptions - -Kotlin has no concept of checked exceptions, all Kotlin exceptions are unchecked. -Swift has only checked errors. So if Swift or Objective-C code calls a Kotlin method -which throws an exception to be handled, then the Kotlin method should be marked -with a `@Throws` annotation specifying a list of "expected" exception classes. - -When compiling to Objective-C/Swift framework, non-`suspend` functions having or inheriting -`@Throws` annotation are represented as `NSError*`-producing methods in Objective-C -and as `throws` methods in Swift. Representations for `suspend` functions always have -`NSError*`/`Error` parameter in completion handler. - -When Kotlin function called from Swift/Objective-C code throws an exception -which is an instance of one of the `@Throws`-specified classes or their subclasses, -it is propagated as `NSError`. Other Kotlin exceptions reaching Swift/Objective-C -are considered unhandled and cause program termination. - -`suspend` functions without `@Throws` propagate only -`CancellationException` as `NSError`. Non-`suspend` functions without `@Throws` -don't propagate Kotlin exceptions at all. - -Note that the opposite reversed translation is not implemented yet: -Swift/Objective-C error-throwing methods aren't imported to Kotlin as -exception-throwing. - -### Extensions and category members - -Members of Objective-C categories and Swift extensions are imported to Kotlin -as extensions. That's why these declarations can't be overridden in Kotlin. -And the extension initializers aren't available as Kotlin constructors. - -Kotlin extensions to "regular" Kotlin classes are imported to Swift and Objective-C as extensions and category members respectively. -Kotlin extensions to other types are treated as [top-level declarations](#top-level-functions-and-properties) -with an additional receiver parameter. These types include: - -* Kotlin `String` type -* Kotlin collection types and subtypes -* Kotlin `interface` types -* Kotlin primitive types -* Kotlin `inline` classes -* Kotlin `Any` type -* Kotlin function types and subtypes -* Objective-C classes and protocols - -### Kotlin singletons - -Kotlin singleton (made with an `object` declaration, including `companion object`) -is imported to Swift/Objective-C as a class with a single instance. -The instance is available through the factory method, i.e. as -`[MySingleton mySingleton]` in Objective-C and `MySingleton()` in Swift. - -### NSNumber - -Kotlin primitive type boxes are mapped to special Swift/Objective-C classes. -For example, `kotlin.Int` box is represented as `KotlinInt` class instance in Swift -(or `${prefix}Int` instance in Objective-C, where `prefix` is the framework names prefix). -These classes are derived from `NSNumber`, so the instances are proper `NSNumber`s -supporting all corresponding operations. - -`NSNumber` type is not automatically translated to Kotlin primitive types -when used as a Swift/Objective-C parameter type or return value. -The reason is that `NSNumber` type doesn't provide enough information -about a wrapped primitive value type, i.e. `NSNumber` is statically not known -to be a e.g. `Byte`, `Boolean`, or `Double`. So Kotlin primitive values -should be cast to/from `NSNumber` manually (see [below](#casting-between-mapped-types)). - -### NSMutableString - -`NSMutableString` Objective-C class is not available from Kotlin. -All instances of `NSMutableString` are copied when passed to Kotlin. - -### Collections - -Kotlin collections are converted to Swift/Objective-C collections as described -in the table above. Swift/Objective-C collections are mapped to Kotlin in the same way, -except for `NSMutableSet` and `NSMutableDictionary`. `NSMutableSet` isn't converted to -a Kotlin `MutableSet`. To pass an object for Kotlin `MutableSet`, -you can create this kind of Kotlin collection explicitly by either creating it -in Kotlin with e.g. `mutableSetOf()`, or using the `KotlinMutableSet` class in Swift -(or `${prefix}MutableSet` in Objective-C, where `prefix` is the framework names prefix). -The same holds for `MutableMap`. - -### Function types - -Kotlin function-typed objects (e.g. lambdas) are converted to -Swift functions / Objective-C blocks. However there is a difference in how -types of parameters and return values are mapped when translating a function -and a function type. In the latter case primitive types are mapped to their -boxed representation. Kotlin `Unit` return value is represented -as a corresponding `Unit` singleton in Swift/Objective-C. The value of this singleton -can be retrieved in the same way as it is for any other Kotlin `object` -(see singletons in the table above). -To sum the things up: - -
- -```kotlin -fun foo(block: (Int) -> Unit) { ... } -``` - -
- -would be represented in Swift as - -
- -```swift -func foo(block: (KotlinInt) -> KotlinUnit) -``` - -
- -and can be called like - -
- -```kotlin -foo { - bar($0 as! Int32) - return KotlinUnit() -} -``` - -
- -### Generics - -Objective-C supports "lightweight generics" defined on classes, with a relatively limited feature set. Swift can import -generics defined on classes to help provide additional type information to the compiler. - -Generic feature support for Objective-C and Swift differ from Kotlin, so the translation will inevitably lose some information, -but the features supported retain meaningful information. - -#### Limitations - -Objective-C generics do not support all features of either Kotlin or Swift, so there will be some information lost -in the translation. - -Generics can only be defined on classes, not on interfaces (protocols in Objective-C and Swift) or functions. - -#### Nullability - -Kotlin and Swift both define nullability as part of the type specification, while Objective-C defines nullability on methods -and properties of a type. As such, the following: - -
- -```kotlin -class Sample() { - fun myVal(): T -} -``` - -
- -will (logically) look like this: - -
- -```swift -class Sample() { - fun myVal(): T? -} -``` - -
- -In order to support a potentially nullable type, the Objective-C header needs to define `myVal` with a nullable return value. - -To mitigate this, when defining your generic classes, if the generic type should *never* be null, provide a non-null -type constraint: - -
- -```kotlin -class Sample() { - fun myVal(): T -} -``` - -
- -That will force the Objective-C header to mark `myVal` as non-null. - -#### Variance - -Objective-C allows generics to be declared covariant or contravariant. Swift has no support for variance. Generic classes coming -from Objective-C can be force-cast as needed. - -
- -```kotlin -data class SomeData(val num: Int = 42) : BaseData() -class GenVarOut(val arg: T) -``` - -
- -
- -```swift -let variOut = GenVarOut(arg: sd) -let variOutAny : GenVarOut = variOut as! GenVarOut -``` - -
- -#### Constraints - -In Kotlin you can provide upper bounds for a generic type. Objective-C also supports this, but that support is unavailable -in more complex cases, and is currently not supported in the Kotlin - Objective-C interop. The exception here being a non-null -upper bound will make Objective-C methods/properties non-null. - -### To disable - -To have the framework header written without generics, add the flag to the compiler config: - -
- -```kotlin -binaries.framework { - freeCompilerArgs += "-Xno-objc-generics" -} -``` - -
- -## Casting between mapped types - -When writing Kotlin code, an object may need to be converted from a Kotlin type -to the equivalent Swift/Objective-C type (or vice versa). In this case a plain old -Kotlin cast can be used, e.g. - -
- -```kotlin -val nsArray = listOf(1, 2, 3) as NSArray -val string = nsString as String -val nsNumber = 42 as NSNumber -``` - -
- -## Subclassing - -### Subclassing Kotlin classes and interfaces from Swift/Objective-C - -Kotlin classes and interfaces can be subclassed by Swift/Objective-C classes -and protocols. - -### Subclassing Swift/Objective-C classes and protocols from Kotlin - -Swift/Objective-C classes and protocols can be subclassed with a Kotlin `final` class. -Non-`final` Kotlin classes inheriting Swift/Objective-C types aren't supported yet, so it is -not possible to declare a complex class hierarchy inheriting Swift/Objective-C types. - -Normal methods can be overridden using the `override` Kotlin keyword. In this case -the overriding method must have the same parameter names as the overridden one. - -Sometimes it is required to override initializers, e.g. when subclassing `UIViewController`. -Initializers imported as Kotlin constructors can be overridden by Kotlin constructors -marked with the `@OverrideInit` annotation: - -
- -```swift -class ViewController : UIViewController { - @OverrideInit constructor(coder: NSCoder) : super(coder) - - ... -} -``` - -
- -The overriding constructor must have the same parameter names and types as the overridden one. - -To override different methods with clashing Kotlin signatures, you can add a -`@Suppress("CONFLICTING_OVERLOADS")` annotation to the class. - -By default the Kotlin/Native compiler doesn't allow calling a non-designated -Objective-C initializer as a `super(...)` constructor. This behaviour can be -inconvenient if the designated initializers aren't marked properly in the Objective-C -library. Adding a `disableDesignatedInitializerChecks = true` to the `.def` file for -this library would disable these compiler checks. - -## C features - -See [INTEROP.md](INTEROP.md) for an example case where the library uses some plain C features -(e.g. unsafe pointers, structs etc.). - -## Unsupported - -Some features of Kotlin programming language are not yet mapped into respective features of Objective-C or Swift. -Currently, following features are not properly exposed in generated framework headers: - * inline classes (arguments are mapped as either underlying primitive type or `id`) - * custom classes implementing standard Kotlin collection interfaces (`List`, `Map`, `Set`) and other special classes - * Kotlin subclasses of Objective-C classes +The content of this page is moved to https://kotlinlang.org/docs/native-objc-interop.html \ No newline at end of file diff --git a/kotlin-native/PLATFORM_LIBS.md b/kotlin-native/PLATFORM_LIBS.md index b62f59f2205..aef7fc223c9 100644 --- a/kotlin-native/PLATFORM_LIBS.md +++ b/kotlin-native/PLATFORM_LIBS.md @@ -1,61 +1,3 @@ # Platform libraries -## Overview - -To provide access to user's native operating system services, -`Kotlin/Native` distribution includes a set of prebuilt libraries specific to -each target. We call them **Platform Libraries**. - -### POSIX bindings - -For all `Unix` or `Windows` based targets (including `Android` and -`iOS`) we provide the `posix` platform lib. It contains bindings -to platform's implementation of `POSIX` standard. - -To use the library just - -
- -```kotlin -import platform.posix.* -``` - -
- -The only target for which it is not available is [WebAssembly](https://en.wikipedia.org/wiki/WebAssembly). - -Note that the content of `platform.posix` is NOT identical on -different platforms, in the same way as different `POSIX` implementations -are a little different. - - -### Popular native libraries - -There are many more platform libraries available for host and -cross-compilation targets. `Kotlin/Native` distribution provides access to -`OpenGL`, `zlib` and other popular native libraries on -applicable platforms. - -On Apple platforms `objc` library is provided for interoperability with [Objective-C](https://en.wikipedia.org/wiki/Objective-C). - -Inspect the contents of `dist/klib/platform/$target` of the distribution for the details. - -## Availability by default - -The packages from platform libraries are available by default. No -special link flags need to be specified to use them. `Kotlin/Native` -compiler automatically detects which of the platform libraries have -been accessed and automatically links the needed libraries. - -On the other hand, the platform libs in the distribution are merely -just wrappers and bindings to the native libraries. That means the -native libraries themselves (`.so`, `.a`, `.dylib`, `.dll` etc) -should be installed on the machine. - -## Examples - -`Kotlin/Native` installation provides a wide spectrum of examples -demonstrating the use of platform libraries. -See [samples](https://github.com/JetBrains/kotlin-native/tree/master/samples) for details. - - +The content of this page is moved to https://kotlinlang.org/docs/native-platform-libs.html \ No newline at end of file