4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rustその2Advent Calendar 2018

Day 14

RustでMac内でLinux用のコードのマクロを展開したコードを取得する方法

Posted at

Rustその2 Advent Calendar 2018の14日目の記事です。

mioの実装を読むという記事を書いていたのですが、記述量が多くなって来たので、Mac内でLinux用のコードのマクロを展開したコードを取得する方法という内容だけ別記事に切り出しました。

まず、mioはRustの低レイヤーな非同期ioライブラリなのですが、内部はLinuxならepoll、Mac(BSD)ならkqueueを使うという実装になっています。(Windowsは...)

epoll.rsdlsym!(fn epoll_create1(c_int) -> c_int);というマクロを使っている所があります。

impl Selector {
    pub fn new() -> io::Result<Selector> {
        let epfd = unsafe {
            // Emulate `epoll_create` by using `epoll_create1` if it's available
            // and otherwise falling back to `epoll_create` followed by a call to
            // set the CLOEXEC flag.
            dlsym!(fn epoll_create1(c_int) -> c_int);

            match epoll_create1.get() {
                Some(epoll_create1_fn) => {
                    cvt(epoll_create1_fn(libc::EPOLL_CLOEXEC))?
                }
                None => {
                    let fd = cvt(libc::epoll_create(1024))?;
                    drop(set_cloexec(fd));
                    fd
                }
            }
        };
        ...
    }
    ...
}

マクロはdlsym.rs内に下記のものがあります。

macro_rules! dlsym {
    (fn $name:ident($($t:ty),*) -> $ret:ty) => (
        #[allow(bad_style)]
        static $name: ::sys::unix::dlsym::DlSym<unsafe extern fn($($t),*) -> $ret> =
            ::sys::unix::dlsym::DlSym {
                name: concat!(stringify!($name), "\0"),
                addr: ::std::sync::atomic::ATOMIC_USIZE_INIT,
                _marker: ::std::marker::PhantomData,
            };
    )
}

<unsafe extern fn($($t),*) -> $ret>は文法的に
<unsafe extern "C" fn ... -> ...> となると思ったんだけど、マクロ内には "C" が無いんだよな...と思い、これを展開したものを見たかったので調べたらcargo expandでマクロを展開出来ることを知りました。
ただ、上のロジックはMac(BSD)では通らないので、 単純にcargo expand しただけではみることが出来ません...
なので、 Linux用にコンパイルする必要があります。幸いRustはクロスコンパイル出来きます。
いける!と思ったのですが、rustupのデフォルトをnightlyにしないと上手く動かず、半日潰しました...

# rustupを事前にインストールしdefaultをnightlyにする
# クロスコンパイル用のmuslをインストール
$ brew install FiloSottile/musl-cross/musl-cross
# x86_64-unknown-linux-muslのコンパイル環境をセットアップ
$ rustup target add x86_64-unknown-linux-musl
# linux用のマクロを展開したソースコードを取得
$ cargo expand --release --target=x86_64-unknown-linux-musl

展開した結果が下記になります。

impl Selector {
    pub fn new() -> io::Result<Selector> {
        let epfd = unsafe {
            #[allow(bad_style)]
            static epoll_create1: ::sys::unix::dlsym::DlSym<unsafe extern "C" fn(c_int) -> c_int> =
            ::sys::unix::dlsym::DlSym{
                name:"epoll_create1\u{0}",
                addr: ::std::sync::atomic::ATOMIC_USIZE_INIT,
                _marker: ::std::marker::PhantomData,
            };

            match epoll_create1.get() {
                Some(epoll_create1_fn) => {
                    cvt(epoll_create1_fn(libc::EPOLL_CLOEXEC))?
                }
                None => {
                    let fd = cvt(libc::epoll_create(1024))?;
                    drop(set_cloexec(fd));
                    fd
                }
            }
        };
        ...
    }
    ...
}

展開してみると<unsafe extern "C" fn(c_int) -> c_int>にちゃんとなっています...:thinking:
何でだろう...
そもそも、FFIを調べてみるとextern fnでも良いけど、expand時に補ってくれているだけかも...?

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?