Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What is going on with this article?
@t10471

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

More than 1 year has passed since last update.

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時に補ってくれているだけかも...?

1
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
t10471
mercari
フリマアプリ「メルカリ」を、グローバルで開発しています。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
1
Help us understand the problem. What is going on with this article?