
本文讨论了使用Kotlin Native创建PHP扩展的最幼稚和最简单的方法。 我提请您注意不是
使用而是
使用的事实。
它是一种教程,描述了刺猬与刺猬杂交时出现的问题以及解决方法。 不会有任何启示,但也许有人会派上用场。
所以,如果有兴趣的话,欢迎来猫。
目的是编写带有一个函数`hello($ name)`的扩展,该扩展函数接受一个字符串并输出`Hello,$ name!`。
顾名思义,我们将天真地决定。
- 让我们在Kotlin上编写一个函数
- 在共享库中编译
- 以经典方式(在C中),我们编写了一个扩展,该扩展会将函数调用重定向到该库
看起来很简单,但是耙子已经潜伏在茂密的草丛中:
- 有很多在Kotlin中使用C库的示例,但是我找不到足够的东西来使用C中的Kotlin库的功能(嗯,也许我看上去很糟糕,实际上是什么)
- kotlinc编译器在首次启动时会加载依赖项。 但是不幸的是我在公司云中的Linux虚拟机。 没有甚至没有理论上的访问互联网的能力。
- 缺乏C经验的人很有可能会因此而陷入困境,但是我将告诉您链接程序如何显着诱骗我。
一切都发生在Red Hat Enterprise Linux Server 7.5版上。走吧
首先,请安装...否,不是Kotlin编译器。 首先,安装JDK。 像那样
然后安装Kotlin编译器。 只需
从github下载
存档,然后将其解压缩到例如主目录即可。
在理想的世界中,他从一开始就亲自下载了所有依赖项,但是,在没有Internet的情况下,我们按以下步骤进行操作(秘密知识是从JetBrains员工那里获得的)。
- 我们创建任何简单的Kotlin脚本,以便下一步可以在编译器上添加一些内容
- 我们启动$ KOTLIN_HOME / bin / kotlinc SimpleScript.kt,稍等一下然后按CTRL + C-这是在主目录中创建一个文件夹结构
- 我们在具有我们的体系结构的部分中,查看文件$ KOTLIN_HOME / konan / konan.properties,并找到以下项目:
dependencies.linux_x64 = \ clang-llvm-5.0.0-linux-x86-64 \ target-gcc-toolchain-3-linux-x86-64 \ libffi-3.2.1-2-linux-x86-64
- 我们转到一个特殊的存储库,并下载以上所有内容。
- 我们将所有这些添加到〜/ .konan / cache中(我提醒您Linux主目录是波浪号)
现在,在第一次开始时,编译器将使用这些发行版,并且不会进入Internet。
请注意,依赖项的大小不是很小,安装后,我的主目录变得重3.4 GB。 对于那些需要单独完成作业的人来说,这很关键。
之后,使用标准的软件包管理器,安装php和相应的php-devel。
至此,准备措施已经结束。
由于不值得讨论编写PHP扩展,因此我们将以尽可能短的代码来解决。
让我们从Kotlin开始
hellokt.kt fun kt_print(string:String){ println("Hello, $string!!!") }
在各种手册和教程中,kotlinc或konanc被用作编译器,这有些令人困惑。 所以-这是同一回事。 这是证明:
编译中
# $KOTLINC_HOME/kotlinc -opt ./hellokt.kt -o hellokt -produce dynamic
使用-opt
开关,库较小。
-produce dynamic告诉编译器为当前平台做一个
共享库 。
执行后,我们将有两个文件:libhellokt.so和hellokt_api.h。 库和头文件。 请注意,前缀和后缀是自动生成的,我们不能(可能)影响它们。
在我们的例子中,我们得到了这样的头文件。
#ifndef KONAN_HELLOKT_H #define KONAN_HELLOKT_H #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus typedef bool hellokt_KBoolean; #else typedef _Bool hellokt_KBoolean; #endif typedef char hellokt_KByte; typedef unsigned short hellokt_KChar; typedef short hellokt_KShort; typedef int hellokt_KInt; typedef long long hellokt_KLong; typedef float hellokt_KFloat; typedef double hellokt_KDouble; typedef void* hellokt_KNativePtr; struct hellokt_KType; typedef struct hellokt_KType hellokt_KType; typedef struct { void (*DisposeStablePointer)(hellokt_KNativePtr ptr); void (*DisposeString)(const char* string); hellokt_KBoolean (*IsInstance)(hellokt_KNativePtr ref, const hellokt_KType* type); struct { struct { void (*kt_print)(const char* string); } root; } kotlin; } hellokt_ExportedSymbols; extern hellokt_ExportedSymbols* hellokt_symbols(void); #ifdef __cplusplus } #endif #endif
访问我们的kt_print函数将以这种方式进行。
hellokt_symbols()->kotlin.root.kt_print(char *);
我将在下面告诉您有关类和包的信息-有细微差别。库已准备就绪,转到C
config.m4 (
如何创建 )
PHP_ARG_ENABLE(hello, whether to enable hello support,[ --enable-hello Enable hello support]) if test "$PHP_HELLO" != "no"; then PHP_ADD_LIBRARY_WITH_PATH(hellokt, /path/to/compiled/library, HELLO_SHARED_LIBADD) PHP_NEW_EXTENSION(hello, hello.c, $ext_shared) PHP_SUBST(HELLO_SHARED_LIBADD) fi
第一行是必需的!
除了几个注释之外,在上面的示例config.m4中看到的第一件事是使用PHP_ARG_WITH()和PHP_ARG_ENABLE()的三行代码。
...
每个扩展都应该至少提供一个扩展名,以便用户选择是否将扩展构建到PHP中。
请注意,在PHP_ADD_LIBRARY_WITH_PATH中,第一个参数是库的名称。 不是libhellokt,即hellokt。 我杀死了两个小时,直到发现ld找不到图书馆的原因。 (在这里,他是有关链接程序欺负的应许故事)。
现在,实际上,扩展代码本身
你好 #include "php.h"
有很多关于编写PHP扩展的文章,并且提供了文档,因此我将只
限于使用zend_parse_parameters的链接-它将就位。
好吧,那么一切都在滚动的道路上:
# $PHP_PATH/phpize # ./configure --with-php-config=$PHP_PATH/php-config # make # $PHP_PATH/php -dextension=./modules/hello.so -r "echo hello('World');" Hello, World!!!
关于类和包的奖金
假设我们想进行风水测试并屏蔽此代码。
package hello.kt; public class HelloKt { fun kt_print(string: String) { println("Hello, $string!!!") } }
这里没有办法进行常规方法调用-您首先必须创建一个类并将其第一个参数传递给被调用的函数。
hellokt_kref_hello_kt_HelloKt helloKt = { 0 }; if(!helloKt.pinned){ helloKt = hellokt_symbols()->kotlin.root.hello.kt.HelloKt.HelloKt(); } hellokt_symbols()->kotlin.root.hello.kt.HelloKt.kt_print(helloKt, name);
接下来是什么? 拒绝共享库,最大程度地减少了对C的使用,这简直不是在开玩笑,微型框架就是这样。 祝我好运! :)