update(docs): replace doc content with links to kotlinlang.ord pages
This commit is contained in:
committed by
Vasily Levchenko
parent
41a1e462f0
commit
c2b1c7df53
+1
-749
@@ -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/).
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="ruby" data-highlight-only>
|
||||
|
||||
```ruby
|
||||
$ sudo gem install cocoapods
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
2. Install the [`cocoapods-generate`](https://github.com/square/cocoapods-generate) plugin.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="ruby" data-highlight-only>
|
||||
|
||||
```ruby
|
||||
$ sudo gem install cocoapods-generate
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
3. In `build.gradle.kts` (or `build.gradle`) of your IDEA project, apply the CocoaPods plugin as well as the Kotlin
|
||||
Multiplatform plugin.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
plugins {
|
||||
kotlin("multiplatform") version "{{ site.data.releases.latest.version }}"
|
||||
kotlin("native.cocoapods") version "{{ site.data.releases.latest.version }}"
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
4. Configure `summary`, `homepage`, and `frameworkName`of the `Podspec` file in the `cocoapods` block.
|
||||
`version` is a version of the Gradle project.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```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"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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}
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
kotlin {
|
||||
ios()
|
||||
|
||||
cocoapods {
|
||||
|
||||
ios.deploymentTarget = "13.5"
|
||||
|
||||
summary = "CocoaPods test library"
|
||||
homepage = "https://github.com/JetBrains/kotlin"
|
||||
|
||||
pod("AFNetworking") {
|
||||
version = "~> 4.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
3. Re-import the project.
|
||||
|
||||
To use these dependencies from the Kotlin code, import the packages `cocoapods.<library-name>`.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
import cocoapods.AFNetworking.*
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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}
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```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"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
> 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.<library-name>`.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
import cocoapods.pod_dependency.*
|
||||
import cocoapods.subspec_dependency.*
|
||||
import cocoapods.AFNetworking.*
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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}
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
3. Re-import the project.
|
||||
|
||||
> To work correctly with Xcode, you should specify the path to the Podspec in your Podfile.
|
||||
> For example:
|
||||
>
|
||||
> <div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
>
|
||||
> ```ruby
|
||||
> target 'ios-app' do
|
||||
> # ... other pod depedencies ...
|
||||
> pod 'JSONModel', :path => '../cocoapods/kotlin-with-cocoapods-sample/kotlin-library/build/cocoapods/externalSources/git/JSONModel'
|
||||
> end
|
||||
> ```
|
||||
>
|
||||
> </div>
|
||||
>
|
||||
{:.note}
|
||||
|
||||
To use these dependencies from the Kotlin code, import the packages `cocoapods.<library-name>`.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
import cocoapods.AFNetworking.*
|
||||
import cocoapods.JSONModel.*
|
||||
import cocoapods.CocoaLumberjack.*
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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}
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
3. Re-import the project.
|
||||
|
||||
> To work correctly with Xcode, you should specify the path to the Podspec in your Podfile.
|
||||
> For example:
|
||||
>
|
||||
> <div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
>
|
||||
> ```ruby
|
||||
> target 'ios-app' do
|
||||
> # ... other pod depedencies ...
|
||||
> pod 'podspecWithFilesExample', :path => '../cocoapods/kotlin-with-cocoapods-sample/pod_dependency'
|
||||
> end
|
||||
> ```
|
||||
>
|
||||
> </div>
|
||||
>
|
||||
{:.note}
|
||||
|
||||
To use these dependencies from the Kotlin code, import the packages `cocoapods.<library-name>`.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
import cocoapods.pod_dependency.*
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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}
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```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")
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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:
|
||||
>
|
||||
> <div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
>
|
||||
> ```ruby
|
||||
> source 'https://github.com/Kotlin/kotlin-cocoapods-spec.git'
|
||||
> ```
|
||||
>
|
||||
> </div>
|
||||
>
|
||||
> You should also specify the path to the Podspec in your Podfile.
|
||||
> For example:
|
||||
>
|
||||
> <div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
>
|
||||
> ```ruby
|
||||
> target 'ios-app' do
|
||||
> # ... other pod depedencies ...
|
||||
> pod 'podspecWithFilesExample', :path => '../cocoapods/kotlin-with-cocoapods-sample/pod_dependency'
|
||||
> end
|
||||
> ```
|
||||
>
|
||||
> </div>
|
||||
>
|
||||
{:.note}
|
||||
|
||||
To use these dependencies from the Kotlin code, import the packages `cocoapods.<library-name>`.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
import cocoapods.example.*
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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 <packageName>`.
|
||||
|
||||
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}
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
kotlin {
|
||||
ios()
|
||||
|
||||
cocoapods {
|
||||
summary = "CocoaPods test library"
|
||||
homepage = "https://github.com/JetBrains/kotlin"
|
||||
|
||||
ios.deploymentTarget = "13.5"
|
||||
|
||||
useLibraries()
|
||||
|
||||
pod("YandexMapKit") {
|
||||
packageName = "YandexMK"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
3. Re-import the project.
|
||||
|
||||
To use these dependencies from the Kotlin code, import the packages `cocoapods.<library-name>`.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
import cocoapods.YandexMapKit.*
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
If you use the `packageName` parameter, you can import the library using the package name: `import <packageName>`:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
import YandexMK.YMKPoint
|
||||
import YandexMK.YMKDistance
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### 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}
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
kotlin {
|
||||
ios()
|
||||
|
||||
cocoapods {
|
||||
summary = "CocoaPods test library"
|
||||
homepage = "https://github.com/JetBrains/kotlin"
|
||||
|
||||
ios.deploymentTarget = "13.5"
|
||||
|
||||
pod("YandexMapKit") {
|
||||
version = "~> 3.2"
|
||||
}
|
||||
useLibraries()
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
4. Re-import the project.
|
||||
|
||||
To use these dependencies from the Kotlin code, import the packages `cocoapods.<library-name>`.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
import cocoapods.YandexMapKit.*
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### 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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```ruby
|
||||
target 'ios-app' do
|
||||
# ... other depedencies ...
|
||||
pod 'podspecWithFilesExample', :path => 'cocoapods/externalSources/url/podspecWithFilesExample'
|
||||
end
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```ruby
|
||||
source 'https://github.com/Kotlin/kotlin-cocoapods-spec.git'
|
||||
|
||||
target 'kotlin-cocoapods-xcproj' do
|
||||
# ... other depedencies ...
|
||||
pod 'example'
|
||||
end
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
> 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}
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```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")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
4. Add the name and path of the Kotlin Pod you want to include in the Xcode project to `Podfile`.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="ruby" data-highlight-only>
|
||||
|
||||
```ruby
|
||||
use_frameworks!
|
||||
|
||||
platform :ios, '13.5'
|
||||
|
||||
target 'ios-app' do
|
||||
pod 'kotlin_library', :path => '../kotlin-library'
|
||||
end
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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}
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
5. Add the name and path of the Kotlin Pod you want to include in the Xcode project to the `Podfile`.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="ruby" data-highlight-only>
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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
|
||||
@@ -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.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```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")
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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.
|
||||
|
||||
<a name="transfer"></a>
|
||||
### 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.
|
||||
|
||||
<a name="detach"></a>
|
||||
### Object subgraph detachment
|
||||
|
||||
An object subgraph without external references can be disconnected using `DetachedObjectGraph<T>` 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<T>.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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val graph = DetachedObjectGraph {
|
||||
val map = mutableMapOf<String, String>()
|
||||
for (entry in map.entries) {
|
||||
// ...
|
||||
}
|
||||
map
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
will not work as expected and will throw runtime exception, as there are uncollected cycles in the detached graph, while:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val graph = DetachedObjectGraph {
|
||||
{
|
||||
val map = mutableMapOf<String, String>()
|
||||
for (entry in map.entries) {
|
||||
// ...
|
||||
}
|
||||
map
|
||||
}().also {
|
||||
kotlin.native.internal.GC.collect()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
will work properly, as holding references will be released, and then cyclic garbage affecting reference counter is
|
||||
collected.
|
||||
|
||||
<a name="shared"></a>
|
||||
### 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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="c">
|
||||
|
||||
```c
|
||||
package = global
|
||||
|
||||
---
|
||||
typedef struct {
|
||||
int version;
|
||||
void* kotlinObject;
|
||||
} SharedData;
|
||||
|
||||
SharedData sharedData;
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
class SharedData(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
var version: Int
|
||||
var kotlinObject: COpaquePointer?
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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.
|
||||
|
||||
<a name="top_level"></a>
|
||||
### 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.
|
||||
|
||||
<a name="atomic_references"></a>
|
||||
### 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.
|
||||
The content of this page is moved to https://kotlinlang.org/docs/native-concurrency.html
|
||||
+1
-261
@@ -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.<br/>
|
||||
_Example:_
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
0:b-debugger-fixes:minamoto@unit-703(0)# cat - > hello.kt
|
||||
fun main(args: Array<String>) {
|
||||
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<kotlin.String>)
|
||||
Breakpoint 1: where = terminator.kexe`kfun:main(kotlin.Array<kotlin.String>) + 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<kotlin.String>) at hello.kt:2
|
||||
1 fun main(args: Array<String>) {
|
||||
-> 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<kotlin.String>) at hello.kt:3
|
||||
1 fun main(args: Array<String>) {
|
||||
2 println("Hello world")
|
||||
-> 3 println("I need your clothes, your boots and your motocycle")
|
||||
4 }
|
||||
(lldb)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Breakpoints
|
||||
Modern debuggers provide several ways to set a breakpoint, see below for a tool-by-tool breakdown:
|
||||
|
||||
#### lldb
|
||||
- by name
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
(lldb) b -n kfun:main(kotlin.Array<kotlin.String>)
|
||||
Breakpoint 4: where = terminator.kexe`kfun:main(kotlin.Array<kotlin.String>) + 4 at hello.kt:2, address = 0x00000001000012e4
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
_``-n`` is optional, this flag is applied by default_
|
||||
- by location (filename, line number)
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
(lldb) b -f hello.kt -l 1
|
||||
Breakpoint 1: where = terminator.kexe`kfun:main(kotlin.Array<kotlin.String>) + 4 at hello.kt:2, address = 0x00000001000012e4
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
- by address
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
(lldb) b -a 0x00000001000012e4
|
||||
Breakpoint 2: address = 0x00000001000012e4
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
- by regex, you might find it useful for debugging generated artifacts, like lambda etc. (where used ``#`` symbol in name).
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
3: regex = 'main\(', locations = 1
|
||||
3.1: where = terminator.kexe`kfun:main(kotlin.Array<kotlin.String>) + 4 at hello.kt:2, address = terminator.kexe[0x00000001000012e4], unresolved, hit count = 0
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
#### gdb
|
||||
- by regex
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
(gdb) rbreak main(
|
||||
Breakpoint 1 at 0x1000109b4
|
||||
struct ktype:kotlin.Unit &kfun:main(kotlin.Array<kotlin.String>);
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
- by name __unusable__, because ``:`` is a separator for the breakpoint by location
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
(gdb) b kfun:main(kotlin.Array<kotlin.String>)
|
||||
No source file named kfun.
|
||||
Make breakpoint pending on future shared library load? (y or [n]) y
|
||||
Breakpoint 1 (kfun:main(kotlin.Array<kotlin.String>)) pending
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
- by location
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
(gdb) b hello.kt:1
|
||||
Breakpoint 2 at 0x100001704: file /Users/minamoto/ws/.git-trees/hello.kt, line 1.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
- by address
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```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.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### 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`:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
λ cat main.kt | nl
|
||||
1 fun main(args: Array<String>) {
|
||||
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<kotlin.String>) + 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<kotlin.String>) 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)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
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):
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```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<String>) {
|
||||
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<kotlin.String>) + 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<kotlin.String>) 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)
|
||||
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### 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
|
||||
+1
-206
@@ -1,206 +1 @@
|
||||
### Q: How do I run my program?
|
||||
|
||||
A: Define a top level function `fun main(args: Array<String>)` 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<String>` 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.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="kotlin" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
kotlin {
|
||||
iosArm64("mylib") {
|
||||
binaries.sharedLib()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="kotlin" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
kotlin {
|
||||
iosArm64("mylib") {
|
||||
binaries.staticLib()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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.
|
||||
|
||||
<div class="multi-language-sample" data-lang="kotlin">
|
||||
<div class="sample" markdown="1" theme="idea" mode="kotlin" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
kotlin {
|
||||
iosArm64("myapp") {
|
||||
binaries.framework {
|
||||
freeCompilerArgs += listOf("-module-name", "TheName")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="multi-language-sample" data-lang="groovy">
|
||||
<div class="sample" markdown="1" theme="idea" mode="groovy">
|
||||
|
||||
```groovy
|
||||
kotlin {
|
||||
iosArm64("myapp") {
|
||||
binaries.framework {
|
||||
freeCompilerArgs += ["-module-name", "TheName"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
### Q: How do I rename the iOS framework? (default name is _\<project name\>_.framework)
|
||||
|
||||
A: Use the `baseName` option. This will also set the module name.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="kotlin" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
kotlin {
|
||||
iosArm64("myapp") {
|
||||
binaries {
|
||||
framework {
|
||||
baseName = "TheName"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### 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:
|
||||
<div class="sample" markdown="1" theme="idea" mode="kotlin" data-highlight-only>
|
||||
|
||||
```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.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>For the CLI, you can compile using gradle as stated in the README (and if you get errors, you can try to do a <code>./gradlew clean</code>):</summary>
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
./gradlew dependencies:update
|
||||
./gradlew dist distPlatformLibs
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
You can then set the `KONAN_HOME` env variable to the generated `dist` folder in the git repository.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>For Gradle, you can use <a href="https://docs.gradle.org/current/userguide/composite_builds.html">Gradle composite builds</a> like this:</summary>
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
</details>
|
||||
The content of this page is moved to https://kotlinlang.org/docs/native-faq.html
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
+1
-720
@@ -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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
|
||||
cd samples/gitchurn
|
||||
../../dist/bin/cinterop -def src/nativeInterop/cinterop/libgit2.def \
|
||||
-compiler-option -I/usr/local/include -o libgit2
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Compile the client:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
../../dist/bin/kotlinc src/gitChurnMain/kotlin \
|
||||
-library libgit2 -o GitChurn
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Run the client:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
./GitChurn.kexe ../..
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
## 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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="c">
|
||||
|
||||
```c
|
||||
headers = png.h
|
||||
headerFilter = png.h
|
||||
package = png
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
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):
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
cinterop -def png.def -compiler-option -I/usr/local/include -o png
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
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 <SomeLibrary/Header.h>`, then it would probably be
|
||||
correct to filter headers with
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="c">
|
||||
|
||||
```c
|
||||
headerFilter = SomeLibrary/**
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="c">
|
||||
|
||||
```c
|
||||
headers = OpenGL/gl.h OpenGL/glu.h GLUT/glut.h
|
||||
compilerOpts = -framework OpenGL -framework GLUT
|
||||
excludeDependentModules = true
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
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
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="c">
|
||||
|
||||
```c
|
||||
compilerOpts = -DFOO=bar
|
||||
linkerOpts = -lpng
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Target-specific options, only applicable to the certain target can be specified as well, such as
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="c">
|
||||
|
||||
```c
|
||||
compilerOpts = -DBAR=bar
|
||||
compilerOpts.linux_x64 = -DFOO=foo1
|
||||
compilerOpts.mac_x64 = -DFOO=foo2
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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 `---`:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="c">
|
||||
|
||||
```c
|
||||
headers = errno.h
|
||||
|
||||
---
|
||||
|
||||
static inline int getErrno() {
|
||||
return errno;
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="c">
|
||||
|
||||
```c
|
||||
headers = foo.h
|
||||
staticLibraries = libfoo.a
|
||||
libraryPaths = /opt/local/lib /usr/local/opt/curl/lib
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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<T>?`.
|
||||
* 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<T>` it is `CPointerVar<T>`, 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<T>` must be one of the "lvalue" types
|
||||
described above, e.g., the C type `struct S*` is mapped to `CPointer<S>`,
|
||||
`int8_t*` is mapped to `CPointer<int_8tVar>`, and `char**` is mapped to
|
||||
`CPointer<CPointerVar<ByteVar>>`.
|
||||
|
||||
C null pointer is represented as Kotlin's `null`, and the pointer type
|
||||
`CPointer<T>` is not nullable, but the `CPointer<T>?` is. The values of this
|
||||
type support all the Kotlin operations related to handling `null`, e.g. `?:`, `?.`,
|
||||
`!!` etc.:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val path = getenv("PATH")?.toKString() ?: ""
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Since the arrays are also mapped to `CPointer<T>`, it supports the `[]` operator
|
||||
for accessing values by index:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
fun shift(ptr: CPointer<BytePtr>, length: Int) {
|
||||
for (index in 0 .. length - 2) {
|
||||
ptr[index] = ptr[index + 1]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
The `.pointed` property for `CPointer<T>` 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<T>`, e.g.:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val intPtr = bytePtr.reinterpret<IntVar>()
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
or
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val intPtr: CPointer<IntVar> = bytePtr.reinterpret()
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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<T>?` and `Long` available,
|
||||
provided by the `.toLong()` and `.toCPointer<T>()` extension methods:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val longValue = ptr.toLong()
|
||||
val originalPtr = longValue.toCPointer<T>()
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val byteVar = placement.alloc<ByteVar>()
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
or
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val bytePtr = placement.allocArray<ByteVar>(5)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val buffer = nativeHeap.allocArray<ByteVar>(size)
|
||||
<use buffer>
|
||||
nativeHeap.free(buffer)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val fileSize = memScoped {
|
||||
val statBuf = alloc<stat>()
|
||||
val error = stat("/", statBuf.ptr)
|
||||
statBuf.st_size
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Passing pointers to bindings ###
|
||||
|
||||
Although C pointers are mapped to the `CPointer<T>` type, the C function
|
||||
pointer-typed parameters are mapped to `CValuesRef<T>`. When passing
|
||||
`CPointer<T>` 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<T>` 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<CPointer<T>?>.toCValues()`, `List<CPointer<T>?>.toCValues()`
|
||||
* `cValuesOf(vararg elements: ${type})`, where `type` is a primitive or pointer
|
||||
|
||||
For example:
|
||||
|
||||
C:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="c">
|
||||
|
||||
```c
|
||||
void foo(int* elements, int count);
|
||||
...
|
||||
int elements[] = {1, 2, 3};
|
||||
foo(elements, 3);
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Kotlin:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
foo(cValuesOf(1, 2, 3), 3)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### 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<ByteVar>.toKString(): String`
|
||||
* `val String.cstr: CValuesRef<ByteVar>`.
|
||||
|
||||
To get the pointer, `.cstr` should be allocated in native memory, e.g.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```
|
||||
val cString = kotlinString.cstr.getPointer(nativeHeap)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="c">
|
||||
|
||||
```c
|
||||
noStringConversion = LoadCursorA LoadCursorW
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
This way any value of type `CPointer<ByteVar>` can be passed as an argument of `const char*` type.
|
||||
If a Kotlin string should be passed, code like this could be used:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
memScoped {
|
||||
LoadCursorA(null, "cursor.bmp".cstr.ptr) // for ASCII version
|
||||
LoadCursorW(null, "cursor.bmp".wcstr.ptr) // for Unicode version
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Scope-local pointers ###
|
||||
|
||||
It is possible to create a scope-stable pointer of C representation of `CValues<T>`
|
||||
instance using the `CValues<T>.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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
memScoped {
|
||||
items = arrayOfNulls<CPointer<ITEM>?>(6)
|
||||
arrayOf("one", "two").forEachIndexed { index, value -> items[index] = value.cstr.ptr }
|
||||
menu = new_menu("Menu".cstr.ptr, items.toCValues().ptr)
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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<T>`.
|
||||
|
||||
`CValue<T>` 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<T>`. Converts (the lvalue) `T` to a `CValue<T>`.
|
||||
So to construct the `CValue<T>`, `T` can be allocated, filled, and then
|
||||
converted to `CValue<T>`.
|
||||
|
||||
* `CValue<T>.useContents(block: T.() -> R): R`. Temporarily places the
|
||||
`CValue<T>` 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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val fieldValue = structValue.useContents { field }
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### 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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val stableRef = StableRef.create(kotlinReference)
|
||||
val voidPtr = stableRef.asCPointer()
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
where the `voidPtr` is a `COpaquePointer` and can be passed to the C function.
|
||||
|
||||
To unwrap the reference:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val stableRef = voidPtr.asStableRef<KotlinClass>()
|
||||
val kotlinReference = stableRef.get()
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
where `kotlinReference` is the original wrapped reference.
|
||||
|
||||
The created `StableRef` should eventually be manually disposed using
|
||||
the `.dispose()` method to prevent memory leaks:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
stableRef.dispose()
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="c">
|
||||
|
||||
```c
|
||||
headers = library/base.h
|
||||
|
||||
---
|
||||
|
||||
static inline int foo(int arg) {
|
||||
return FOO(arg);
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### 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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
fun ${type1}.convert<${type2}>(): ${type2}
|
||||
```
|
||||
</div>
|
||||
|
||||
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`:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
fun zeroMemory(buffer: COpaquePointer, size: Int) {
|
||||
memset(buffer, 0, size.convert<size_t>())
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```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.
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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
|
||||
@@ -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<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
|
||||
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<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
|
||||
binaries.withType<org.jetbrains.kotlin.gradle.plugin.mpp.Framework> {
|
||||
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
|
||||
+1
-243
@@ -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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ kotlinc foo.kt -p library -o bar
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
the above command will produce a `bar.klib` with the compiled contents of `foo.kt`.
|
||||
|
||||
To link to a library use the `-library <name>` or `-l <name>` flag. For example:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ kotlinc qux.kt -l bar
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
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
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ cinterop -def samples/gitchurn/src/nativeInterop/cinterop/libgit2.def -compiler-option -I/usr/local/include -o libgit2
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ klib contents <name>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
To inspect the bookkeeping details of the library
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ klib info <name>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
To install the library to the default location use
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ klib install <name>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
To remove the library from the default repository use
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ klib remove <name>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
All of the above commands accept an additional `-repository <directory>` argument for specifying a repository different to the default one.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ klib <command> <name> -repository <directory>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
## Several examples
|
||||
|
||||
First let's create a library.
|
||||
Place the tiny library source code into `kotlinizer.kt`:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```kotlin
|
||||
package kotlinizer
|
||||
val String.kotlinized
|
||||
get() = "Kotlin $this"
|
||||
```
|
||||
|
||||
```bash
|
||||
$ kotlinc kotlinizer.kt -p library -o kotlinizer
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
The library has been created in the current directory:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ ls kotlinizer.klib
|
||||
kotlinizer.klib
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Now let's check out the contents of the library:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ klib contents kotlinizer
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
We can install `kotlinizer` to the default repository:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ klib install kotlinizer
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Remove any traces of it from the current directory:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ rm kotlinizer.klib
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Create a very short program and place it into a `use.kt` :
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
import kotlinizer.*
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println("Hello, ${"world".kotlinized}!")
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Now compile the program linking with the library we have just created:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ kotlinc use.kt -l kotlinizer -o kohello
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
And run the program:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="shell">
|
||||
|
||||
```bash
|
||||
$ ./kohello.kexe
|
||||
Hello, Kotlin world!
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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
|
||||
@@ -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.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
// MyLibraryUtils.kt
|
||||
package my.library
|
||||
|
||||
fun foo() {}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
can be called from Swift like
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="swift">
|
||||
|
||||
```swift
|
||||
MyLibraryUtilsKt.foo()
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### 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.:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="swift">
|
||||
|
||||
```swift
|
||||
[player moveTo:LEFT byMeters:17]
|
||||
[player moveTo:UP byInches:42]
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
in Kotlin it would be:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
player.moveTo(LEFT, byMeters = 17)
|
||||
player.moveTo(UP, byInches = 42)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### 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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
fun foo(block: (Int) -> Unit) { ... }
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
would be represented in Swift as
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="swift">
|
||||
|
||||
```swift
|
||||
func foo(block: (KotlinInt) -> KotlinUnit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
and can be called like
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
foo {
|
||||
bar($0 as! Int32)
|
||||
return KotlinUnit()
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### 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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
class Sample<T>() {
|
||||
fun myVal(): T
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
will (logically) look like this:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="swift">
|
||||
|
||||
```swift
|
||||
class Sample<T>() {
|
||||
fun myVal(): T?
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
class Sample<T : Any>() {
|
||||
fun myVal(): T
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
data class SomeData(val num: Int = 42) : BaseData()
|
||||
class GenVarOut<out T : Any>(val arg: T)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="swift">
|
||||
|
||||
```swift
|
||||
let variOut = GenVarOut<SomeData>(arg: sd)
|
||||
let variOutAny : GenVarOut<BaseData> = variOut as! GenVarOut<BaseData>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
#### 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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
binaries.framework {
|
||||
freeCompilerArgs += "-Xno-objc-generics"
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## 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.
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
val nsArray = listOf(1, 2, 3) as NSArray
|
||||
val string = nsString as String
|
||||
val nsNumber = 42 as NSNumber
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## 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:
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" mode="swift">
|
||||
|
||||
```swift
|
||||
class ViewController : UIViewController {
|
||||
@OverrideInit constructor(coder: NSCoder) : super(coder)
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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
|
||||
@@ -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
|
||||
|
||||
<div class="sample" markdown="1" theme="idea" data-highlight-only>
|
||||
|
||||
```kotlin
|
||||
import platform.posix.*
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user