概要です。
共有ライブラリをつくれば良いことがわかったのでやっていきます。
実装する
型などを定義します。スレッドローカルではない値を定義するために Sync
をつけているんですけど、これが何を意味しているのかは謎です。俺たちは雰囲気で Rust をやっている。
const EXECUTION_SUCCESS: c_int = 0;
const BUILTIN_ENABLED: c_int = 0x01;
#[repr(C)]
pub struct WORD_DESC {
word: *mut c_char,
dollar_present: c_int,
quoted: c_int,
assignment: c_int,
}
#[repr(C)]
pub struct WORD_LIST {
next: *mut WORD_LIST,
word: *mut WORD_DESC,
}
pub type sh_builtin_func_t = extern fn (*mut WORD_LIST) -> c_int;
#[repr(C)]
pub struct builtin {
name: *mut c_char,
function: sh_builtin_func_t,
flags: c_int,
long_doc: *mut *const c_char,
short_doc: *mut c_char,
handle: *mut c_char,
}
unsafe impl Sync for builtin {}
コマンドを実装します。文字列の定義がとにかく厳しくて、null 終端の byte string を二回キャストしてポインタを取るみたいなことをしています。
pub extern fn hello_world(_list: *mut WORD_LIST) -> c_int {
println!("Hello, World!");
EXECUTION_SUCCESS
}
const LONG_DOC: &'static [*const c_char] = &[
b"Show a greeting message.\0" as *const _ as *const _,
b"\0" as *const _ as *const _,
b"It's far faster than launching executable file\0" as *const _ as *const _,
b"because it't not necessary to call exec() and fork().\0" as *const _ as *const _,
0 as *const _,
];
#[no_mangle]
pub static mut hello_world_struct: builtin = builtin {
name: b"hello_world\0" as *const _ as *mut _,
function: hello_world,
flags: BUILTIN_ENABLED,
long_doc: LONG_DOC as *const _ as *mut _,
short_doc: b"hello_world\0" as *const _ as *mut _,
handle: 0 as *mut _,
};
共有ライブラリとしてビルドします。cdylib
と書くべきところを dylib
と書いて少しハマりました。具体的には、リリースビルドをしたときに文字列のあたりがおかしくなります。
Cargo.toml
[package]
name = "hello_world"
version = "0.1.0"
authors = []
[lib]
name = "hello_world"
path = "./lib.rs"
crate-type = ["cdylib"]
$ cargo build --release
Compiling hello_world v0.1.0 (file:///Users/woxtu/Workspace/hello_world)
Finished release [optimized] target(s) in 0.29 secs
以上です。
呼び出す
先につくった共有ライブラリを組み込みます。
$ enable -f target/release/libhello_world.dylib hello_world
$ enable | grep hello_world
enable hello_world
コマンドを呼び出します。
$ hello_world
Hello, World!
$ help hello_world
hello_world: hello_world
Show a greeting message.
It's far faster than launching executable file
because it't not necessary to call exec() and fork().
やりました。以上です。
終わりに
組み込みコマンドはともかく、共有ライブラリがつくれるということは他言語との連携も取りやすいということなので、仲良くしていくと良いんじゃないかと思います。各位、仲良く。
コードは Gist に上げてあります。