qemu-irix 无法在 Alpine 3.10 (GCC 8.3) 下构建

qemu-irix fails to build under Alpine 3.10 (GCC 8.3)

只是为了好玩,我正在尝试将 irixxxx's qemu-irix 构建为 Docker 图像。

它在 Debian Buster 下成功构建(使用 GCC 8 容器)。但是,它无法在 Alpine 3.10 下构建(仅当我选择 Irix 目标时才会失败),并出现以下错误(在 make 阶段):

  CC      util/oslib-posix.o
In file included from util/oslib-posix.c:39:
/usr/include/sys/signal.h:1:2: warning: #warning redirecting incorrect #include <sys/signal.h> to <signal.h> [-Wcpp]
 #warning redirecting incorrect #include <sys/signal.h> to <signal.h>
  ^~~~~~~
  CC      util/qemu-openpty.o
util/qemu-openpty.c: In function 'qemu_openpty_raw':
util/qemu-openpty.c:123:9: warning: implicit declaration of function 'openpty'; did you mean 'openat'? [-Wimplicit-function-declaration]
     if (openpty(&amaster, aslave, pty_buf, NULL, NULL) < 0) {
         ^~~~~~~
         openat
util/qemu-openpty.c:123:9: warning: nested extern declaration of 'openpty' [-Wnested-externs]

(...)

  CC      irix-linux-user/linux-user/syscall.o
/qemu-irix/linux-user/syscall.c:6784:22: error: 'F_EXLCK' undeclared here (not in a function); did you mean 'F_RDLCK'?
     TRANSTBL_CONVERT(F_EXLCK),
                      ^~~~~~~
/qemu-irix/linux-user/syscall.c:6779:51: note: in definition of macro 'TRANSTBL_CONVERT'
 #define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
                                                   ^
/qemu-irix/linux-user/syscall.c:6785:22: error: 'F_SHLCK' undeclared here (not in a function); did you mean 'F_RDLCK'?
     TRANSTBL_CONVERT(F_SHLCK),
                      ^~~~~~~
/qemu-irix/linux-user/syscall.c:6779:51: note: in definition of macro 'TRANSTBL_CONVERT'
 #define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
                                                   ^
In file included from /qemu-irix/linux-user/syscall.c:121:
/qemu-irix/linux-user/syscall.c: In function 'target_to_host_sigevent':
/qemu-irix/linux-user/syscall.c:7422:27: error: 'struct sigevent' has no member named '_sigev_un'; did you mean 'sigev_value'?
     __get_user(host_sevp->_sigev_un._tid, &target_sevp->_sigev_un._tid);
                           ^~~~~~~~~
/qemu-irix/linux-user/qemu.h:501:5: note: in definition of macro '__get_user_e'
   ((x) = (typeof(*hptr))(                                               \
     ^
/qemu-irix/linux-user/syscall.c:7422:5: note: in expansion of macro '__get_user'
     __get_user(host_sevp->_sigev_un._tid, &target_sevp->_sigev_un._tid);
     ^~~~~~~~~~
/qemu-irix/linux-user/syscall.c:7422:36: error: '(const bitmask_transtbl *)&<erroneous-expression>' is a pointer; did you mean to use '->'?
     __get_user(host_sevp->_sigev_un._tid, &target_sevp->_sigev_un._tid);
                                    ^
/qemu-irix/linux-user/qemu.h:501:5: note: in definition of macro '__get_user_e'
   ((x) = (typeof(*hptr))(                                               \
     ^
/qemu-irix/linux-user/syscall.c:7422:5: note: in expansion of macro '__get_user'
     __get_user(host_sevp->_sigev_un._tid, &target_sevp->_sigev_un._tid);
     ^~~~~~~~~~
/qemu-irix/linux-user/qemu.h:506:13: warning: left-hand operand of comma expression has no effect [-Wunused-value]
      (hptr)), (void)0)
             ^
/qemu-irix/linux-user/qemu.h:510:31: note: in expansion of macro '__get_user_e'
 # define __get_user(x, hptr)  __get_user_e(x, hptr, be)
                               ^~~~~~~~~~~~
/qemu-irix/linux-user/syscall.c:7422:5: note: in expansion of macro '__get_user'
     __get_user(host_sevp->_sigev_un._tid, &target_sevp->_sigev_un._tid);
     ^~~~~~~~~~
/qemu-irix/linux-user/syscall.c: In function 'do_syscall':
/qemu-irix/linux-user/syscall.c:13545:25: warning: implicit declaration of function 'sethostid'; did you mean 'gethostid'? [-Wimplicit-function-declaration]
         ret = get_errno(sethostid(arg1));
                         ^~~~~~~~~
                         gethostid
/qemu-irix/linux-user/syscall.c:13545:25: warning: nested extern declaration of 'sethostid' [-Wnested-externs]
make[1]: *** [/qemu-irix/rules.mak:66: linux-user/syscall.o] Error 1
make: *** [Makefile:472: subdir-irix-linux-user] Error 2
The command '/bin/sh -c make && DESTDIR=/tmp/qemu make install' returned a non-zero code: 2

我研究了Debian的GCC和Alpine的GCC(其实就是libc6和musl)在类似故障方面的区别,但是没找到不修改代码如何解决的资料。

那么,我在哪里可以找到有关此问题的更多信息以及哪些软件包可以解决此问题?谢谢

Docker 文件和完整日志 here. Docker container image (Debian Buster) here

差异似乎是由底层 libc 实现引起的:Alpine 的 glibc of Debian, vs musl-libc

虽然 GNU libc 是 Linux 中事实上的标准 libc 实现,但 musl libc 被少数发行版使用,例如 Alpine Linux 和 Void Linux。 musl 是一个简约的 strict-POSIX libc 实现,通常与 glibc 不兼容。通常,软件项目必须移植到 musl libc 才能在 Alpine 上得到支持,尤其是非平凡的应用程序。

syscall.c 的编译在几个地方中断,第一个是:

/qemu-irix/linux-user/syscall.c:6784:22: error: 'F_EXLCK' undeclared here (not in a function); did you mean 'F_RDLCK'?
 TRANSTBL_CONVERT(F_EXLCK)

F_EXLCK is 宏未在 musl libc 的 fcntl.h 中定义。但是,可以通过手动定义它来轻松修补它,例如 make CFLAGS='"-DF_EXLCK=4"'。这就是 qemu 为非 irix 目标 (patch link) 的 musl 打补丁的方式。

但是,还有更多未定义的宏,例如 __SIGRTMIN__SIGRTMAX、宏 TRANSTBL_CONVERT,可能还有其他宏。临时修补它们可能还不够——所以看来 qemu-irix 项目必须正确移植到 Alpine 和 musl libc。

如果你愿意,你可以尝试遵循现有的 qemu musl 补丁,并尝试自己为 qemu-irix 打补丁:
- https://lists.gnu.org/archive/html/qemu-devel/2014-04/msg04773.html
- https://github.com/NixOS/nixpkgs/pull/46449/files

题外话评论,用make -j并行构建,会结束得更快