ギリギリまでstatic linkされたWindows版qemuをビルドしたい会
ちょっと依存関係が多くて配付が面倒なので。。
- mingw-w64-ucrt-x86_64-libslirp
- mingw-w64-ucrt-x86_64-glib2
- mingw-w64-ucrt-x86_64-pixman
- mingw-w64-ucrt-x86_64-virglrenderer
- mingw-w64-ucrt-x86_64-angleproject
- mingw-w64-ucrt-x86_64-SDL2
ANGLEはヘッダを他所から持ってくれば問題ないはず。SDL2はまぁ普通にCMakeで良いよな。残りは絶妙に難しい。
glib2
Windows向けのinstructionは一応 https://gitlab.gnome.org/GNOME/glib/-/blob/main/docs/win32-build.md に有るが、大したことは書かれていない。 https://download.gnome.org/sources/glib/2.83/glib-2.83.2.tar.xz からDLして展開する。
tar: glib-2.83.2/COPYING: Cannot create symlink to ‘LICENSES/LGPL-2.1-or-later.txt’: No such file or directory
まぁsymlinkは気にしないって事で。。
ERROR: This python3 seems to be msys/python on MSYS2 Windows, but you are in a MinGW environment
ERROR: Please install it via https://packages.msys2.org/base/mingw-w64-python
mesonって専用版が要るのか。。 mingw-w64-ucrt-x86_64-meson
をインストール。
WARNING: failed to download with error: could not get https://github.com/PCRE2Project/pcre2/releases
/download/pcre2-10.44/pcre2-10.44.tar.bz2 is the internet available?. Trying after a delay...
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issue
r certificate (_ssl.c:1000)>
ca-certificates
ってデフォルトインストールじゃないのか。。 mingw-w64-ucrt-x86_64-ca-certificates
をインストール。
subprojectsはWebやGitから拾ってくるため、 git
も必要になる。
最終的に /ucrt64/bin/meson .. --prefix=/opt/qemudeps --buildtype=debug -Ddefault_library=static
でconfigureした。
libsilrp
https://gitlab.freedesktop.org/slirp/libslirp 。https://gitlab.freedesktop.org/slirp/libslirp/-/releases/v4.8.0 からDLして展開する。
移植層としてはGlibを使っている。というわけで、pkg-configを設定しておく。
$ export PKG_CONFIG_PATH=/opt/qemudeps/lib/pkgconfig
何ごとも無くインストールできた。
pixman
https://www.cairographics.org/releases/pixman-0.44.2.tar.xz からDLして展開。リポジトリ https://gitlab.freedesktop.org/pixman/pixman には特にコレといった説明は無いな。。 これもsymlinkがアーカイブ中にあるが、GitLab CIの内部なので無視。
これも何ごともなくインストールできた。
virglrenderer
https://gitlab.freedesktop.org/virgl/virglrenderer/-/releases/1.1.0 からかな。。今年の6月 https://zenn.dev/link/comments/6f6e07f28d9be2 に見つけたバグは治っているようだ。
libepoxy
libepoxyが依存のようだ。 https://github.com/anholt/libepoxy/releases/tag/1.5.10 からDLしてくる。ヘッダ類もepoxyが提供するものを使っているのかな。
Windows上では何故かEGLをビルドしない。
/ucrt64/bin/meson .. --prefix=/opt/qemudeps --buildtype=debug -Ddefault_library=static -Degl=yes
mingw-w64-ucrt-x86_64-egl-headers
と mingw-w64-ucrt-x86_64-gles-headers
が必要。
SDL2
これはmesonではなくCMakeなので mingw-w64-ucrt-x86_64-cmake
が必要。
/ucrt64/bin/cmake -G Ninja -DSDL_STATIC=ON -DSDL_SHARED=OFF -DSDL_TEST=OFF -DSDL_OPENGL=OFF -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/opt/qemudeps ..
でconfigureしてみる。
... ビルドはできるけど /lib/libSDL2d.a
になっちゃうな。。まぁ手でコピーすれば良いか。
qemu (一周目)
おい誰だよ dllimport
してる奴。。
E:/msys64_qemu/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld
.exe: libcommon.a.p/net_slirp.c.obj: in function `net_slirp_state_load':
E:\msys64_qemu\home\oku\qemu\build/../net/slirp.c:404:(.text+0x1d3): undefined reference to `__imp_s
lirp_state_load'
半年前とか何十年歴史あるライブラリなのに修正されたの最近すぎるだろ。。
一旦手動で修正。
余計なものを探す
libffi-8.dll => /ucrt64/bin/libffi-8.dll (0x7ffd7b160000)
libintl-8.dll => /ucrt64/bin/libintl-8.dll (0x7ffd66430000)
libbz2-1.dll => /ucrt64/bin/libbz2-1.dll (0x7ffd79070000)
libiconv-2.dll => /ucrt64/bin/libiconv-2.dll (0x7ffcf7d60000)
libwinpthread-1.dll => /ucrt64/bin/libwinpthread-1.dll (0x7ffd782f0000)
libcurl-4.dll => /ucrt64/bin/libcurl-4.dll (0x7ffcf7110000)
zlib1.dll => /ucrt64/bin/zlib1.dll (0x7ffd66410000)
libncursesw6.dll => /ucrt64/bin/libncursesw6.dll (0x7ffd657b0000)
libzstd.dll => /ucrt64/bin/libzstd.dll (0x7ffcf5d70000)
libidn2-0.dll => /ucrt64/bin/libidn2-0.dll (0x7ffd65760000)
libbrotlidec.dll => /ucrt64/bin/libbrotlidec.dll (0x7ffd65740000)
libnghttp2-14.dll => /ucrt64/bin/libnghttp2-14.dll (0x7ffd4a930000)
libnghttp3-9.dll => /ucrt64/bin/libnghttp3-9.dll (0x7ffd469a0000)
libpsl-5.dll => /ucrt64/bin/libpsl-5.dll (0x7ffd60870000)
libcrypto-3-x64.dll => /ucrt64/bin/libcrypto-3-x64.dll (0x7ffceb6d0000)
libssl-3-x64.dll => /ucrt64/bin/libssl-3-x64.dll (0x7ffd423d0000)
libssh2-1.dll => /ucrt64/bin/libssh2-1.dll (0x7ffd42880000)
libbrotlicommon.dll => /ucrt64/bin/libbrotlicommon.dll (0x7ffd55090000)
libunistring-5.dll => /ucrt64/bin/libunistring-5.dll (0x7ffcf2c90000)
libunistring-5.dll => /ucrt64/bin/libunistring-5.dll (0x1598cf80000)
そもそもnghttpとかどうやってビルド環境に紛れこんだんだよ。。(たぶんgccとかpython類だとは思うけど)
Dependenciesでねっとりと確認したところ:
- libffi → gio が gobject をリンクしている関係
- libintl
- libbz2
- libcurl
- libiconv
- libncursesw6 → これが intl と iconv をpull in しているっぽい
- zlib1
- libzstd
これで勝負:
../configure --enable-whpx --enable-system --enable-slirp --enable-vnc \
--target-list=aarch64-softmmu,arm-softmmu,avr-softmmu,riscv32-softmmu,riscv64-softmmu,x86_64-softmmu \
--prefix=e:/qemutmp \
--disable-gio --disable-curl --disable-zstd --disable-bzip2 --disable-curses
qemu (二周目)
まだ libintl が居る。。
glib-2.0.pc:Libs: -L${libdir} -lglib-2.0 -lintl -latomic -lm -lws2_32 -lwinmm
glibだった。libintl外せるのかな。。 configureに --static
を渡すと、
E:/msys64_qemu/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld
.exe: E:/msys64_qemu/ucrt64/lib/libintl.a(dcigettext.o):(.text+0x6d9): undefined reference to `libic
onv_open'
iconvがリンクされずに失敗してしまう。
qemu(三周目)
とりあえず glib-2.0.pc
を
Libs: -L${libdir} -lglib-2.0 -liconv -lintl -latomic -lm -lws2_32 -lwinmm
みたいに -liconv
を入れてみたけど、そもそもqemu自体にiconvサポートがあるんだからそっちを有効にすれば良いよね。。とりあえずこれでリンクに成功した。
qemu(四周目)
../configure --enable-whpx --enable-system --enable-slirp --enable-vnc --target-list=aarch64-softmmu,arm-softmmu,avr-softmmu,riscv32-softmmu,riscv64-softmmu,x86_64-softmmu --prefix=e:/qemutmp --disable-gio --disable-curl --disable-zstd --disable-bzip2 --disable-curses --static --extra-ldflags=-liconv
libsilrp
以外は手動パッチなしになった。...が、起動しない。。
起動しないのはGLESが無いせいだった。 https://github.com/mmozeiko/build-angle からDLしたらちゃんと起動した。
ビルドスクリプトを書く
結局のところ、ビルドツールは全てNinja、SDL以外はconfigureに meson
という構成だった。subprojectは後で処理するとして、一括でビルドできるようにスクリプト化するのが良いかな。
今回は Docker コンテナで作業することにした。
volumeの生成
tmp
、 libs
と dist
の3つのvolumeを用意する。
$ docker volume create tmp
$ docker volume create libs
$ docker volume create dist
ライブラリのconfigure / compile / install
ライブラリは glib → libslirp → pixman → libepoxy → virglrenderer の順でビルドする。
docker run --isolation process -t \
-vtmp:c:\\objs -vlibs:c:\\libs -ve:/repos/qemubuild:c:\\srcs \
qemubuild c:\\msys64\\msys2_shell.cmd -here -no-start -ucrt64 -defterm \
-c "PKG_CONFIG_PATH=c:/libs/lib/pkgconfig /ucrt64/bin/meson setup --prefix=c:/libs --buildtype=release -Ddefault_library=static c:/srcs/deps/libslirp c:/objs/libslirp"
コンパイルとインストールはどちらも meson
がwrap しているのでそれを使う。後で destdir を一旦変更してからインストールする方式にしよう。。
yaml
モジュールが無くて失敗した
ModuleNotFoundError: No module named 'yaml'
virglrendererのgitソースのビルドには要るのか。。
docker run --isolation process --rm -vtmp:c:\\objs -vlibs:c:\\libs -ve:/repos/qemubuild:c:\\srcs \
qemubuild c:\\msys64\\msys2_shell.cmd -here -no-start -ucrt64 -defterm \
-c "pacman --noconfirm -S mingw-w64-ucrt-x86_64-python-yaml && PKG_CONFIG_PATH=c:/libs/lib/pkgconfig /ucrt64/bin/meson compile -C c:/objs/virglrenderer"
後でDockerイメージに足しておく。
SDL2
SDL2はCMakeプロジェクトなのでconfigure方法が違う。
docker run --isolation process --rm -vtmp:c:\\objs -vlibs:c:\\libs -ve:/repos/qemubuild:c:\\srcs \
qemubuild c:\\msys64\\msys2_shell.cmd -here -no-start -ucrt64 -defterm \
-c "/ucrt64/bin/cmake -G Ninja -DSDL_STATIC=ON -DSDL_SHARED=OFF -DSDL_OPENGL=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=c:/libs -B c:/objs/SDL2 -S c:/srcs/deps/SDL2"
CMakeにも --build <dir>
と --install <dir>
がある。
qemu
満を持して dist
をマウント。
docker run --isolation process --rm -vtmp:c:\\objs -vlibs:c:\\libs -vdist:c:\\dist -ve:/repos/qemubuild:c:\\srcs qemubuild \
c:\\msys64\\msys2_shell.cmd -here -no-start -ucrt64 -defterm \
-c "mkdir -p c:/objs/qemu && cd c:/objs/qemu && PKG_CONFIG_PATH=c:/libs/lib/pkgconfig c:/srcs/qemu/configure --enable-whpx --enable-system --enable-slirp --enable-vnc --target-list=aarch64-softmmu,arm-softmmu,avr-softmmu,riscv32-softmmu,riscv64-softmmu,x86_64-softmmu --prefix=c:/dist --disable-gio --disable-curl --disable-zstd --disable-bzip2 --disable-curses --static --extra-ldflags=-liconv"
内部的にはmesonなんだけど一応 ninja -C
で代用する。
-Werror
に当たる
C:/srcs/qemu/net/slirp.c: In function 'net_slirp_poll_notify':
C:/srcs/qemu/net/slirp.c:366:9: error: 'slirp_pollfds_fill' is deprecated [-Werror=deprecated-declarations]
366 | slirp_pollfds_fill(s->slirp, &poll->timeout,
| ^~~~~~~~~~~~~~~~~~
In file included from C:/srcs/qemu/net/slirp.c:41:
c:/libs/include/slirp/libslirp.h:273:6: note: declared here
273 | void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
| ^~~~~~~~~~~~~~~~~~
cc1.exe: all warnings being treated as errors
漢は黙って --disable-werror
。一旦ABIを破壊する変更が入り、その後追加のコミットで復活 + deprecateされたようだ。 ...というかqemuみたいな大口顧客を無視してアップデートするのは良いんだろうか。。
qemu側はリリース待ち。
さらにstatic buildのために --extra-cflags=-DLIBSLIRP_STATIC
が要るのか。。
ファイルの取り出し
普通にシェルを使うのが簡単かな。。
docker run --isolation process --rm -vdist:c:\\dist -ve:/repos/qemubuild/out:c:\\out qemubuild \
c:\\msys64\\msys2_shell.cmd -here -no-start -ucrt64 -defterm \
-c "cp -rp c:/dist/* c:/out/"
EGLを有効にするの忘れた
qemu-system-x86_64.exe: OpenGL support was not enabled in this build of QEMU
確かにqemuのconfigureの時に No って出てるな。。
Run-time dependency epoxy found: YES 1.5.11
Has header "epoxy/egl.h" with dependency epoxy: NO
mesonに -Degl=yes
を渡す必要がある。
docker run --isolation process --rm -vtmp:c:\\objs -vlibs:c:\\libs -ve:/repos/qemubuild:c:\\srcs qemubuild \
c:\\msys64\\msys2_shell.cmd -here -no-start -ucrt64 -defterm \
-c "PKG_CONFIG_PATH=c:/libs/lib/pkgconfig /ucrt64/bin/meson setup --prefix=c:/libs --buildtype=release -Ddefault_library=static -Degl=yes c:/srcs/deps/libepoxy c:/objs/libepoxy"
記事にした