3
0

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 3 years have passed since last update.

D言語Advent Calendar 2021

Day 7

importCさっくり

Posted at

言いたいことはこのツイートで済んでますが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を無効にする方法とかがわからぬ(無理やり無効化したところで動くかもわからぬ)。

3
0
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
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?