
Este artigo discute a abordagem mais ingênua e fácil de criar uma extensão PHP usando o Kotlin Native. Chamo sua atenção para o fato de que não
com , mas
com o uso .
É um tipo de tutorial com uma descrição dos problemas que surgiram ao cruzar um ouriço com um ouriço e maneiras de resolvê-los. Não haverá revelações, mas talvez alguém seja útil.
Então, se estiver interessado, então seja bem-vindo ao gato.
O objetivo é escrever uma extensão com uma função `hello ($ name)` que pegue uma string e imprima `Hello, $ name!`.
Nós decidiremos ingenuamente, como o nome diz.
- Vamos escrever uma função no Kotlin
- Compilar na biblioteca compartilhada
- Da maneira clássica (em C), escrevemos uma extensão que redirecionará uma chamada de função para esta biblioteca
Parece simples, mas um ancinho já estava à espreita na grama densa:
- Existem vários exemplos de uso de bibliotecas C no Kotlin, mas não encontrei nada adequado para usar as funções da biblioteca Kotlin no C (bem, talvez eu estivesse parecendo mal, o que realmente)
- O compilador kotlinc carrega dependências na primeira vez em que é iniciado. Mas a má sorte é minha máquina virtual Linux na nuvem corporativa. Sem, mesmo teórica, a capacidade de acessar a Internet.
- Esse rake é mais provável devido à falta de experiência em C, mas vou lhe contar como o vinculador me trollou notavelmente.
Tudo aconteceu no Red Hat Enterprise Linux Server versão 7.5.Vamos lá!
Para começar, instale ... Não, não o compilador Kotlin. Primeiro, instale o JDK. Bem assim.
Em seguida, instale o compilador Kotlin. Basta baixar o
arquivo no github e descompactá-lo, por exemplo, no diretório inicial.
Em um mundo ideal, no primeiro começo, ele baixa todas as dependências, mas, na ausência da Internet, procedemos da seguinte maneira (o conhecimento secreto é obtido com folga dos funcionários da JetBrains):
- Criamos qualquer script Kotlin simples para que haja algo a ser destacado no compilador na próxima etapa
- Começamos $ KOTLIN_HOME / bin / kotlinc SimpleScript.kt, espere um pouco e pressione CTRL + C - isto é para criar uma estrutura de pastas no diretório inicial
- Examinamos o arquivo $ KOTLIN_HOME / konan / konan.properties, na seção com nossa arquitetura, e procuramos o item:
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
- Vamos a um repositório especial e baixamos todos os itens acima.
- Adicionamos tudo isso ao ~ / .konan / cache (lembro que o diretório inicial do Linux é um til)
Agora, no primeiro início, o compilador usará essas distribuições e não entrará na Internet.
Observe que as dependências não são muito pequenas e, após instalá-las, meu diretório pessoal ficou 3,4 GB mais pesado. Para aqueles que têm um volume separado sob a lição de casa, isso pode ser crítico.
Depois, com o gerenciador de pacotes padrão, instale o php e o php-devel correspondente.
Sobre isso, as medidas preparatórias terminaram.
Como não vale a pena falar em escrever extensões PHP, seguiremos com o menor código possível.
Vamos começar com Kotlin
hellokt.kt fun kt_print(string:String){ println("Hello, $string!!!") }
Em vários manuais e tutoriais, o kotlinc ou o konanc são usados como compiladores, o que é um pouco confuso. Então - é a mesma coisa. Aqui está a prova:
Compilando
# $KOTLINC_HOME/kotlinc -opt ./hellokt.kt -o hellokt -produce dynamic
Com a
opção -opt
, a biblioteca é menor.
-produce dynamic diz ao compilador para fazer uma
biblioteca compartilhada para a plataforma atual.
Após a execução, teremos dois arquivos: libhellokt.so e hellokt_api.h. Biblioteca e arquivo de cabeçalho para ele. Observe que prefixos e sufixos são gerados automaticamente e não podemos influenciá-los (provavelmente).
No nosso caso, obtemos um arquivo de cabeçalho.
#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
O acesso à nossa função kt_print será assim.
hellokt_symbols()->kotlin.root.kt_print(char *);
Vou falar sobre aulas e pacotes abaixo - existem nuances.A biblioteca está pronta, vá para C
config.m4 (
como criá-lo )
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
A primeira linha é necessária!
A primeira coisa vista no exemplo config.m4 acima, além de alguns comentários, são três linhas usando PHP_ARG_WITH () e PHP_ARG_ENABLE ().
...
Cada extensão deve fornecer pelo menos uma ou outra com o nome da extensão, para que os usuários possam optar por criar ou não a extensão no PHP.
Observe que no PHP_ADD_LIBRARY_WITH_PATH, o primeiro argumento é o nome da biblioteca. Não libhellokt, ou seja, hellokt. Eu matei duas horas até descobrir por que ld não consegue encontrar a biblioteca. (aqui está a história prometida sobre o bullying de vinculador).
Agora, de fato, o próprio código de extensão
hello.c #include "php.h"
Existem alguns artigos sobre como escrever extensões PHP, e a documentação está presente, então vou me
limitar a um link para
usar zend_parse_parameters - ele estará no lugar.
Bem, então tudo está no caminho rolado:
# $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!!!
Bônus, sobre aulas e pacotes
Suponha que desejássemos fazer o feng shui e cegar esse código.
package hello.kt; public class HelloKt { fun kt_print(string: String) { println("Hello, $string!!!") } }
Não há como fazer uma chamada de método usual aqui - você primeiro terá que criar uma classe e passar o primeiro argumento para a função chamada.
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);
O que vem a seguir? Rejeição da biblioteca compartilhada, minimizando o uso de C e, o que diabos não está brincando, uma mini estrutura é uma coisa dessas. Deseje-me boa sorte! :)