Cópia estática
Copiado de docs/language/interop.pt-BR.md em https://github.com/poppy-team/ori-lang (MIT). Fixado na revisão 42e1817227fbc96e8e4a4a85fac78b3fec0a0e0f, blob efcb44a731016fc7e600f9321bf66a1f991852fe. O repositório de origem permanece canônico; esta cópia é atualizada por um pull request de sincronização, não em tempo real.
English: interop.mdReferência normativa: 16-runtime-ffi-safety.md e 19-abi.md
Há duas direções de FFI. extern importa um símbolo nativo para o código Ori; @c_export publica uma função public escolhida para que um host C a chame.
module app.embed_add
@c_export
public add_scores(a: int, b: int) -> int
return a + b
endCompile com:
ori compile --lib examples/embed/add_scores.orl -o libadd_scores.soO compilador grava a biblioteca e um header C irmão. O host deve chamar ori_rt_init() antes de usar a biblioteca e ori_rt_shutdown() ao terminar. O header também declara ori_rt_version() e ori_rt_abi_version(); ambas retornam strings NUL-terminadas emprestadas, que o host não deve liberar. Se o host aceitar várias revisões, valide a string ABI antes de chamar os exports.
Bloqueio de segurança em 0.3.8-dev: os construtores de ponteiro cru de
ori-embed::OriValuecontinuam sendo escapes emprestados e explicitamenteunsafe. Valores retornados pela Ori carregam ownership ARC privado e são liberados noDrop; argumentos gerenciados são retidos durante o cleanup do callee, ebytespode ser lido com comprimento exato poras_bytes_with_len(). A sessão ainda é experimental: não fabrique ponteiros, retenha valores crus emprestados nem assuma identidade de geração para um valor criado por construtor raw.
Hosts Rust podem usar o crate experimental ori-embed para uma fronteira de sessão com análise estruturada e uma superfície deliberadamente pequena de JIT persistente:
OriConfig seleciona target, execution profile e features declaradas/ativas;OriEngine verifica fonte em memória e devolve diagnostics estruturados próprios;ModuleId estável e gerações crescentes;main, resolver um handle opaco amarrado à geração e chamar assinaturas homogêneas de bool, int, float, slice, string ou bytes com no máximo quatro argumentos.OriHostRegistry pode registrar uma função escalar extern host uma vez por sessão; o JIT mantém o endereço em cache e não faz lookup a cada chamada.OriHostRegistry::register_int_callback, register_float_callback e register_bool_callback podem registrar callbacks escalares homogêneos com user_data opaco; o JIT injeta um ID estável e faz o dispatch sem lookup textual por chamada. Cada callback aceita até quatro parâmetros do seu tipo escalar e retorna esse mesmo tipo ou void nesta fronteira Rust experimental.remove_callback retorna um trap de cancelamento estruturado, enquanto a remoção durante uma chamada ativa retorna CallbackActive. Reentrada na mesma OriEngine é suportada para chamadas síncronas e a recursão é limitada a 64 frames de callback.OriEngine::unload_module libera as gerações executáveis retidas; os handles passam a falhar em vez de chamar código liberado.check, guards de divisão inteira e bounds diretos de collections/texto escalares) retornam OriExecutionError pela API Rust; não fazem unwind pelo host nem encerram o processo.Isso ainda não é uma API geral de execução nem um sistema completo de hot reload. A ABI C-1 gerada cobre a superfície @c_export descrita abaixo, mas a sessão Rust hospedada ainda não expõe aggregates nem execução assíncrona. Ponteiros gerenciados escalares só têm ownership quando retornados pelo JIT; construtores raw continuam emprestados e unsafe. Caminhos de abort do runtime fora desse conjunto ainda não estão cobertos. O slice de callback é limitado a hosts Rust confiáveis e assinaturas escalares homogêneas; header C, dispatch por afinidade de thread, destruição de objetos e migração durante reload continuam fora. Veja o plano do Host ABI e o plano do compiler service.
A ABI nativa gerada na versão 1 aceita escalares, bool, void, string terminada em NUL, bytes por uma view OriBytes { data, len } (comprimento exato, inclusive NUL interno), structs escalares não vazias e não genéricas por wrappers pointer/out, structs gerenciadas por handles ARC opacos e bridges diretos de optional/result sobre esses payloads.
list, map, set, tuple, unions aninhadas, structs genéricas e structs vazias diretas são rejeitadas. Uma collection pode ficar dentro de uma struct gerenciada, pois seu layout permanece privado.
Parâmetros gerenciados são emprestados. Retornos transferem uma referência ao host, que deve liberá-la com ori_arc_release. Retornos bytes usam OriBytes *out e transferem ownership em out->data.
Restrição para string estrangeira: o wrapper gerado copia entradas
stringantes de passá-las para Ori, inclusive payloads deoptional/result. Código de usuário ainda não deve fabricar nem armazenar ponteiros emprestados do host por uma fuga FFI manual; mantenha o ponteiro válido apenas durante a chamada.
No ori.pkg.toml, seções [native.dependencies.<lib>] (pkg_config, static, framework, version) e [native.linux], [native.windows], [native.macos] (com libraries, frameworks, library_dirs, link_flags) declaram bibliotecas do sistema sem scripts de link manuais:
[native.dependencies.raylib]
pkg_config = "raylib"
version = ">= 5.0"
[native.linux]
libraries = ["GL", "X11", "m", "dl"]
[native.windows]
libraries = ["user32", "opengl32"]
[native.macos]
frameworks = ["OpenGL", "Cocoa"]O compilador resolve pkg-config, traduz os flags para -l, -L e -framework (ou .lib e /LIBPATH no MSVC) e propaga as flags para o linker nativo.
@align) Structs @repr("C") podem receber alinhamento explícito com @align(N) para potências de dois (1 a 64), emitido nos headers C irmãos (alignas(N)/__attribute__((aligned(N)))) para GPU uniform buffers e GDExtension:
@repr("C")
@align(16)
public struct UniformData
matrix: int
offset: int
end@c_export e headers C gerados continuam pertencendo ao backend nativo; a remoção da emissão de código C não remove a interoperabilidade pela ABI C. Callbacks host→Ori continuam fora do header C da ABI-1; a implementação Rust experimental aceita apenas callbacks escalares homogêneos (int, float ou bool). Layouts diretos de collections também continuam fora da ABI-1. ori-embed ainda é uma fronteira experimental e não oferece handles gerenciados seguros. Os nomes exportados precisam ser identificadores portáveis de C/C++.
O caminho completo está em examples/embed.