importCさっくり

この記事の更新版は[こちら](https://qiita.com/dragoon2014/items/3a0674e34572ea86f1f8)

---

言いたいことは[このツイート](https://twitter.com/dragoon_2012/status/1459903927265030148)で済んでますがAdCの時期でせっかくなので記事化しました。

システムが持っているWaylandのライブラリを利用してGUIを出現させてみます。

- 執筆時の D version は 2.098.0
- OSはubuntu 20.04

予めシステムヘッダーのwayland-client.hを同.iに変換します（正直ここが本番）。
C11に忠実なライブラリであればあるほど変換は楽でしょう。
なお後述のSDLの項で影響受けてますが、コンパイラの実装にひっかかって詰む場合もあるので
当該ライブラリ自体が忠実だとしても、だめなときはだめです。

```
$ clang -E -std=c11 \
    -D__extension__= \
    -D__restrict= \
    /usr/include/wayland-client.h \
  | sed -e 's/(void (\*\*)(void))/(void**)/g' \
        -e 's/void (\*\*implementation)(void)/void**/' \
  > wayland_client.i
```

（gccの場合はプリプロセッサに`'-D_Float128=long double'`を足すと動いた）

クライアントのコードを書きます。

Wayland側の参考コード
https://qiita.com/propella/items/d180dd0425ecd99efd42

共有バッファの所を大着するためのmemfd_createがD側に用意されてないので直接定義するとか、
一部castを入れてあげないと型競合してエラーになるとか起きるのでそこは注意。


```
// dmd -L-lwayland-client wl1.d wayland_client.i && ./wl1
import std;
// clang -E -std=c11 -D__extension__= -D__restrict= /usr/include/wayland-client.h |
//   sed -e 's/(void (\*\*)(void))/(void**)/g' -e 's/void (\*\*implementation)(void)/void**/' > wayland_client.i
import wayland_client;
import core.sys.linux.unistd;
import core.sys.linux.sys.mman;

auto myassert(T)(T eval){ writeln(eval); assert(eval); return eval; }

__gshared wl_compositor* g_compositor;
__gshared wl_shell* g_shell;
__gshared wl_shm* g_shm;

extern(C){
    void reg_global(void* data, wl_registry* reg, uint id, const(char)* iface, uint ver){
        auto iface_ = iface.fromStringz;
        switch(iface_){
        case "wl_compositor":
            g_compositor = cast(wl_compositor*)wl_registry_bind(reg, id, &wl_compositor_interface, 1).myassert;
            break;
        case "wl_shell":
            g_shell = cast(wl_shell*)wl_registry_bind(reg, id, &wl_shell_interface, 1).myassert;
            break;
        case "wl_shm":
            g_shm = cast(wl_shm*)wl_registry_bind(reg, id, &wl_shm_interface, 1).myassert;
            break;
        default:
            printf("%p %p %d %s %d\n", data, reg, id, iface, ver);
        }
    }
    void shell_ping(void* data, wl_shell_surface* shsrf, uint serial){
        printf("%p %p %d\n", data, shsrf, serial);
        wl_shell_surface_pong(shsrf, serial);
    }
    int memfd_create(const(char)*, uint);
}

void main(){
    auto dpy = wl_display_connect(null).myassert;
    auto reg = wl_display_get_registry(dpy).myassert;
    wl_registry_add_listener(reg, cast(wl_registry_listener*)[cast(void*)&reg_global, null], null);
    wl_display_roundtrip(dpy);
    auto srf = wl_compositor_create_surface(g_compositor).myassert;
    auto shsrf = wl_shell_get_shell_surface(g_shell, srf);
    wl_shell_surface_set_toplevel(shsrf);
    wl_shell_surface_add_listener(shsrf, cast(wl_shell_surface_listener*)[&shell_ping, null, null], null);
    auto shmfd = memfd_create("".ptr, 0).myassert;
    auto shmsize = 128*128*4;
    ftruncate(shmfd, shmsize);
    void* shmptr = mmap(null, shmsize, PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0).myassert;
    shmptr[0..128*128*4] = iota(128*128*4).map!(a=>uniform!(ubyte)).array;
    auto shmpool = wl_shm_create_pool(g_shm, shmfd, shmsize);
    auto shmbuf = wl_shm_pool_create_buffer(shmpool, 0, 128, 128, 128*4, WL_SHM_FORMAT_ARGB8888);
    wl_shm_pool_destroy(shmpool);
    wl_surface_attach(srf, shmbuf, 0, 0);
    wl_surface_commit(srf);
    while(wl_display_dispatch(dpy) != -1){}
}
```

あとはライブラリを指定してビルド＆実行。

```
$ dmd -L-lwayland-client wl1.d wayland_client.i && ./wl1
```

本編ここまで、以下失敗例

---

SDLでも途中まで試しましたが、定数（SDL_INIT_VIDEOとか）がdefineされてるので蒸発するとかで一筋縄では無理そうでした。


```
$ cat sdl1.d
import std;
import SDL;

void main(){
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
    // 窓を出す実装を書くまでもなく詰んだ
}
```


```
$ clang -E -std=c11 -D__restrict= -D__inline__=inline -D__inline=inline \
    -U__GNUC__ '-D__int128=long long' -fno-gnu-inline-asm \
    /usr/include/SDL2/SDL.h -I/usr/include/SDL2 > SDL.i
$ dmd -L-lSDL2 sdl1.d SDL.i
/usr/include/SDL2/SDL_audio.h(192): Error: struct `SDL.SDL_AudioCVT` no size because of forward reference
Segmentation fault (コアダンプ)
```

```
$ vim SDL.i
(↓xを消す、aとbを入れ替え)
xstruct SDL_AudioCVT;
atypedef void ( * SDL_AudioFilter) (struct SDL_AudioCVT * cvt,
a                                          SDL_AudioFormat format);
b# 226 "/usr/include/SDL2/SDL_audio.h"
btypedef struct SDL_AudioCVT
b{
b    int needed;
b    SDL_AudioFormat src_format;
b    SDL_AudioFormat dst_format;
b    double rate_incr;
b    Uint8 *buf;
b    int len;
b    int len_cvt;
b    int len_mult;
b    double len_ratio;
b    SDL_AudioFilter filters[9 + 1];
b    int filter_index;
b} SDL_AudioCVT;
```

```
$ dmd -L-lSDL2 sdl1.d SDL.i
sdl1.d(5): Error: undefined identifier `SDL_INIT_VIDEO`
sdl1.d(5): Error: undefined identifier `SDL_INIT_EVENTS`
/usr/include/SDL2/SDL_stdinc.h(437): Error: `switch` statement without a `default`; use `final switch` or add `default: assert(0);` or add `default: break;`
/usr/include/SDL2/SDL_stdinc.h(437): Error: `object` is not a member of `void`
/usr/include/SDL2/SDL_stdinc.h(441): Deprecation: switch case fallthrough - use 'goto case;' if intended
/usr/include/SDL2/SDL_stdinc.h(442): Deprecation: switch case fallthrough - use 'goto case;' if intended
/usr/include/SDL2/SDL_stdinc.h(441): Deprecation: switch case fallthrough - use 'goto case;' if intended
/usr/include/SDL2/SDL_stdinc.h(442): Deprecation: switch case fallthrough - use 'goto case;' if intended
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(33): Error: undefined identifier `__builtin_ia32_emms`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(50): Error: undefined identifier `__builtin_ia32_vec_init_v2si`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(67): Error: undefined identifier `__builtin_ia32_vec_ext_v2si`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(129): Error: undefined identifier `__builtin_ia32_packsswb`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(159): Error: undefined identifier `__builtin_ia32_packssdw`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(189): Error: undefined identifier `__builtin_ia32_packuswb`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(216): Error: undefined identifier `__builtin_ia32_punpckhbw`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(239): Error: undefined identifier `__builtin_ia32_punpckhwd`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(260): Error: undefined identifier `__builtin_ia32_punpckhdq`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(287): Error: undefined identifier `__builtin_ia32_punpcklbw`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(310): Error: undefined identifier `__builtin_ia32_punpcklwd`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(331): Error: undefined identifier `__builtin_ia32_punpckldq`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(352): Error: undefined identifier `__builtin_ia32_paddb`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(373): Error: undefined identifier `__builtin_ia32_paddw`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(394): Error: undefined identifier `__builtin_ia32_paddd`
/usr/lib/llvm-10/lib/clang/10.0.0/include/mmintrin.h(416): Error: undefined identifier `__builtin_ia32_paddsb`
```

fallthroughのところはSDLのmasterだと実装が少し変わってるのでそれをつかえば動くかも。
あとintrinsicを無効にする方法とかがわからぬ（無理やり無効化したところで動くかもわからぬ）。