#编程语言 #llvm #安全 #安全包装器 #包装器 #强类型 #编译时

inkwell

墨池旨在帮助您通过安全地包装 llvm-sys 来创建自己的编程语言。

13 个不稳定版本 (5 个破坏性版本)

0.5.0 2024 年 8 月 4 日
0.4.0 2024 年 2 月 3 日
0.3.0 2024 年 1 月 20 日
0.2.0 2023 年 5 月 5 日
0.0.0 2017 年 6 月 29 日

#13 in FFI

Download history 6053/week @ 2024-05-03 7027/week @ 2024-05-10 10317/week @ 2024-05-17 11059/week @ 2024-05-24 9450/week @ 2024-05-31 5975/week @ 2024-06-07 5639/week @ 2024-06-14 4075/week @ 2024-06-21 3648/week @ 2024-06-28 3266/week @ 2024-07-05 4771/week @ 2024-07-12 4112/week @ 2024-07-19 4283/week @ 2024-07-26 4813/week @ 2024-08-02 3721/week @ 2024-08-09 3873/week @ 2024-08-16

17,778 每月下载量
用于 64 个 Crates (30 个直接使用)

Apache-2.0

1MB
13K SLoC

Inkwell(s)

Crates.io Build Status codecov lines of code Join the chat at https://gitter.im/inkwell-rs/Lobby Minimum rustc 1.56

It's a New Kind of Wrapper for Exposing LLVM (Safely)

墨池旨在帮助您通过安全地包装 llvm-sys 来创建自己的编程语言。它提供比底层 LLVM C API 更强的类型接口,以便在编译时而不是在 LLVM 的运行时捕获某些类型的错误。这意味着我们试图尽可能接近地复制 LLVM IR 的强类型。最终目标是使 LLVM 从 Rust 端更安全,并且稍微容易学习(通过文档)和使用。

要求

  • Rust 1.56+ (稳定、Beta 或 Nightly)
  • LLVM 4-18 之一

使用方法

您需要将您的 Cargo.toml 指向使用与您的 LLVM 版本相对应的单个 LLVM 版本功能标志,如下所示

[dependencies]
inkwell = { version = "0.5.0", features = ["llvm18-0"] }

支持版本:LLVM 4-18 映射到 cargo 功能标志 llvmM-0 其中 M 对应于 LLVM 的主要版本。

请注意,由于我们处于预 v1.0.0 阶段,我们可能会不时在 master 上进行破坏性更改,以符合 semver。请尽可能选择 crates.io 发布版!

文档

文档根据 master 自动 部署 到这里。这些文档尚未 100% 完成,并且仅显示最新的支持的 LLVM 版本,由于 rustdoc 的问题。有关更多信息,请参阅 #2

示例

Tari 的 llvm-sys 示例 使用 Inkwell 以安全代码编写1

use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::execution_engine::{ExecutionEngine, JitFunction};
use inkwell::module::Module;
use inkwell::OptimizationLevel;

use std::error::Error;

/// Convenience type alias for the `sum` function.
///
/// Calling this is innately `unsafe` because there's no guarantee it doesn't
/// do `unsafe` operations internally.
type SumFunc = unsafe extern "C" fn(u64, u64, u64) -> u64;

struct CodeGen<'ctx> {
    context: &'ctx Context,
    module: Module<'ctx>,
    builder: Builder<'ctx>,
    execution_engine: ExecutionEngine<'ctx>,
}

impl<'ctx> CodeGen<'ctx> {
    fn jit_compile_sum(&self) -> Option<JitFunction<SumFunc>> {
        let i64_type = self.context.i64_type();
        let fn_type = i64_type.fn_type(&[i64_type.into(), i64_type.into(), i64_type.into()], false);
        let function = self.module.add_function("sum", fn_type, None);
        let basic_block = self.context.append_basic_block(function, "entry");

        self.builder.position_at_end(basic_block);

        let x = function.get_nth_param(0)?.into_int_value();
        let y = function.get_nth_param(1)?.into_int_value();
        let z = function.get_nth_param(2)?.into_int_value();

        let sum = self.builder.build_int_add(x, y, "sum").unwrap();
        let sum = self.builder.build_int_add(sum, z, "sum").unwrap();

        self.builder.build_return(Some(&sum)).unwrap();

        unsafe { self.execution_engine.get_function("sum").ok() }
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    let context = Context::create();
    let module = context.create_module("sum");
    let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None)?;
    let codegen = CodeGen {
        context: &context,
        module,
        builder: context.create_builder(),
        execution_engine,
    };

    let sum = codegen.jit_compile_sum().ok_or("Unable to JIT compile `sum`")?;

    let x = 1u64;
    let y = 2u64;
    let z = 3u64;

    unsafe {
        println!("{} + {} + {} = {}", x, y, z, sum.call(x, y, z));
        assert_eq!(sum.call(x, y, z), x + y + z);
    }

    Ok(())
}

1 在本例中,unsafe有两个用途,因为实际编译和即时执行代码本身固有的unsafe。一方面,我们无法验证是否以正确的函数签名调用get_function()。另外,调用我们得到的功能也是unsafe的,因为没有保证代码本身在内部不执行unsafe操作(这就是为什么调用C时需要unsafe的原因)。

LLVM的Kaleidoscope教程

可在示例目录中找到。

替代包

贡献

查看我们的贡献指南

依赖项

~0.3–1.1MB
~25K SLoC