|
946 | 946 |
|
947 | 947 | <li class="md-nav__item"> |
948 | 948 | <a href="#_2" class="md-nav__link"> |
949 | | - 绑定生成 |
| 949 | + 绑定与桥接生成 |
950 | 950 | </a> |
951 | 951 |
|
952 | | - <nav class="md-nav" aria-label="绑定生成"> |
| 952 | + <nav class="md-nav" aria-label="绑定与桥接生成"> |
953 | 953 | <ul class="md-nav__list"> |
954 | 954 |
|
955 | 955 | <li class="md-nav__item"> |
|
986 | 986 | 构建桥接代码 |
987 | 987 | </a> |
988 | 988 |
|
989 | | -</li> |
990 | | - |
991 | | - </ul> |
992 | | - </nav> |
993 | | - |
994 | 989 | </li> |
995 | 990 |
|
996 | 991 | <li class="md-nav__item"> |
997 | 992 | <a href="#_6" class="md-nav__link"> |
998 | 993 | 原生代码编译 |
999 | 994 | </a> |
1000 | 995 |
|
1001 | | - <nav class="md-nav" aria-label="原生代码编译"> |
1002 | | - <ul class="md-nav__list"> |
| 996 | +</li> |
1003 | 997 |
|
1004 | 998 | <li class="md-nav__item"> |
1005 | 999 | <a href="#klib" class="md-nav__link"> |
|
1019 | 1013 | </li> |
1020 | 1014 |
|
1021 | 1015 | <li class="md-nav__item"> |
1022 | | - <a href="#cinterop" class="md-nav__link"> |
1023 | | - 调试 CInterop 过程 |
| 1016 | + <a href="#ccall" class="md-nav__link"> |
| 1017 | + 编译器处理 @CCall 函数调用 |
1024 | 1018 | </a> |
1025 | 1019 |
|
1026 | 1020 | </li> |
|
2580 | 2574 |
|
2581 | 2575 | <li class="md-nav__item"> |
2582 | 2576 | <a href="#_2" class="md-nav__link"> |
2583 | | - 绑定生成 |
| 2577 | + 绑定与桥接生成 |
2584 | 2578 | </a> |
2585 | 2579 |
|
2586 | | - <nav class="md-nav" aria-label="绑定生成"> |
| 2580 | + <nav class="md-nav" aria-label="绑定与桥接生成"> |
2587 | 2581 | <ul class="md-nav__list"> |
2588 | 2582 |
|
2589 | 2583 | <li class="md-nav__item"> |
|
2620 | 2614 | 构建桥接代码 |
2621 | 2615 | </a> |
2622 | 2616 |
|
2623 | | -</li> |
2624 | | - |
2625 | | - </ul> |
2626 | | - </nav> |
2627 | | - |
2628 | 2617 | </li> |
2629 | 2618 |
|
2630 | 2619 | <li class="md-nav__item"> |
2631 | 2620 | <a href="#_6" class="md-nav__link"> |
2632 | 2621 | 原生代码编译 |
2633 | 2622 | </a> |
2634 | 2623 |
|
2635 | | - <nav class="md-nav" aria-label="原生代码编译"> |
2636 | | - <ul class="md-nav__list"> |
| 2624 | +</li> |
2637 | 2625 |
|
2638 | 2626 | <li class="md-nav__item"> |
2639 | 2627 | <a href="#klib" class="md-nav__link"> |
|
2653 | 2641 | </li> |
2654 | 2642 |
|
2655 | 2643 | <li class="md-nav__item"> |
2656 | | - <a href="#cinterop" class="md-nav__link"> |
2657 | | - 调试 CInterop 过程 |
| 2644 | + <a href="#ccall" class="md-nav__link"> |
| 2645 | + 编译器处理 @CCall 函数调用 |
2658 | 2646 | </a> |
2659 | 2647 |
|
2660 | 2648 | </li> |
@@ -2706,7 +2694,7 @@ <h2 id="_1">接口定义</h2> |
2706 | 2694 | compilerOpts = -Isrc/nativeInterop/cinterop |
2707 | 2695 | </code></pre> |
2708 | 2696 | <p>如上所示,<code>.def</code> 文件定义了 C 接口,包括头文件、编译选项、链接选项等信息。C-interop 工具将解析这个文件,并生成相应的 Kotlin 代码和 KLIB 文件。</p> |
2709 | | -<h2 id="_2">绑定生成</h2> |
| 2697 | +<h2 id="_2">绑定与桥接生成</h2> |
2710 | 2698 | <pre><code>./kotlin-native/dist/bin/run_konan cinterop -def ./compilerTestData/cinterop/hello.def -o compilerTestData/cinterop/Hello -J"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:50015" |
2711 | 2699 | </code></pre> |
2712 | 2700 | <p>当我们执行 C-interop 命令时,实际上是调用了以上命令,这个命令会执行以下操作:</p> |
@@ -2804,7 +2792,7 @@ <h4 id="_5">构建桥接代码</h4> |
2804 | 2792 | // 这样 Kotlin 代码就可以通过这个函数指针安全地调用 C 函数 |
2805 | 2793 | const void* knifunptr_hello0_hello_from_c = (const void*)&hello_hello_from_c_wrapper0; |
2806 | 2794 | </code></pre> |
2807 | | -<h3 id="_6">原生代码编译</h3> |
| 2795 | +<h4 id="_6">原生代码编译</h4> |
2808 | 2796 | <p>上面生成的 C 桥接代码,需要通过 LLVM 编译为 bc 文件。</p> |
2809 | 2797 | <pre><code>when (flavor) { |
2810 | 2798 | KotlinPlatform.NATIVE -> { |
@@ -2836,10 +2824,27 @@ <h4 id="klib">生成 KLIB</h4> |
2836 | 2824 | } |
2837 | 2825 | } |
2838 | 2826 | </code></pre> |
2839 | | -<h2 id="cinterop">调试 CInterop 过程</h2> |
2840 | | -<pre><code>./kotlin-native/dist/bin/run_konan cinterop -def ./compilerTestData/cinterop/hello.def -o compilerTestData/cinterop/Hello -J"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:50015" |
| 2827 | +<h2 id="ccall">编译器处理 @CCall 函数调用</h2> |
| 2828 | +<p>上面生成的 KLIB 文件,包含了 Kotlin IR 存根和桥接代码。接下来,Kotlin 编译器会处理这个 KLIB 文件,将其与 Kotlin 代码进行链接。通过以下命令行执行 Kotlin 编译器:</p> |
| 2829 | +<pre><code>./kotlin-native/dist/bin/run_konan konanc ./compilerTestData/cinterop/Main.kt -library ./compilerTestData/cinterop/Hello.klib -o ./compilerTestData/cinterop/Hello -J"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:50015" |
| 2830 | +</code></pre> |
| 2831 | +<p>同时我们可以看到,上面生成的 knm 中的函数为<code>hello_from_c</code>,而生成的桥接代码中的函数是<code>knifunptr_hello0_hello_from_c</code>,因此 Kotlin 编译器还需要识别<code>@kotlinx.cinterop.internal.CCall</code>函数,并修改调用代码,将其替换为桥接函数。</p> |
| 2832 | +<pre><code class="language-kotlin">// 处理 C 函数调用 |
| 2833 | +if (function.annotations.hasAnnotation(RuntimeNames.cCall)) { |
| 2834 | + return generateCCall(expression)、 |
| 2835 | +} |
2841 | 2836 |
|
2842 | | -./kotlin-native/dist/bin/run_konan konanc ./compilerTestData/cinterop/Main.kt -library ./compilerTestData/cinterop/Hello.klib -o ./compilerTestData/cinterop/Hello -J"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:50015" |
| 2837 | +generateCCall(expression: IrCall, builder: IrBuilderWithScope, isInvoke: Boolean, |
| 2838 | + foreignExceptionMode: ForeignExceptionMode.Mode = ForeignExceptionMode.default): IrExpression { |
| 2839 | + // ... |
| 2840 | + if (isInvoke) { |
| 2841 | + callBuilder.cBridgeBodyLines.add(0, "$targetFunctionVariable = ${targetPtrParameter!!};") |
| 2842 | + } else { |
| 2843 | + val cCallSymbolName = callee.getAnnotationArgumentValue<String>(RuntimeNames.cCall, "id")!! |
| 2844 | + this.addC(listOf("extern const $targetFunctionVariable __asm(\"$cCallSymbolName\");")) // Exported from cinterop stubs. |
| 2845 | + } |
| 2846 | + return result |
| 2847 | +} |
2843 | 2848 | </code></pre> |
2844 | 2849 |
|
2845 | 2850 | <hr> |
|
0 commit comments