如何实际检测 musl libc?
How to actually detect musl libc?
musl 团队声称不需要检测 musl libc 的方法,因为他们只实现了标准功能,没有需要检测的怪癖。
直到今天,这种说法很可能是正确的,但现在已不再正确。正常的功能检测不起作用,因为该功能存在但已损坏,我宁愿不探测它,因为我不想在编译时要求 root 并禁止交叉编译。该错误已通过最小化示例代码报告,维护人员根本不想修复它,也不会接受我的补丁。
我不会惩罚所有其他 libc,因为 musl 有一个损坏的功能。
按理说我想做
#if MUSL || APPLE
pid = fork();
#else
pid = vfork();
#endif
我已经有 #if APPLE
因为 Mac OSX 有一个不可信的 vfork()
.
告诉我 vfork()
不好是没有意义的。自 2008 年以来,情况发生了变化,无论涉及的复杂性如何,只要有可能,vfork()
都是更好的选择。一些来源:https://gist.github.com/nicowilliams/a8a07b0fc75df05f684c23c18d7db234
我想这有点晚了,但这里有一个解决方案:
#! /bin/sh
tmpf=/tmp/musl.log
# Detect Musl C library.
libc=$(ldd /bin/ls | grep 'musl' | head -1 | cut -d ' ' -f1)
if [ -z $libc ]; then
# This is not Musl.
rm -f ${tmpf}
exit 1
fi
$libc >${tmpf} 2>&1
vstr=$(cat ${tmpf} | grep "Version" | cut -d ' ' -f2)
v_major=$(echo $vstr | cut -d '.' -f1)
v_minor=$(echo $vstr | cut -d '.' -f2)
v_patch=$(echo $vstr | cut -d '.' -f3)
rm -f ${tmpf}
echo "-D__MUSL__ -D__MUSL_VER_MAJOR__=${v_major} -D__MUSL_VER_MINOR__=${v_minor} -D__MUSL_VER_PATCH__=${v_patch}"
这个 shell 脚本提取了一些有趣的信息并打印出 -D
友好的值,因此 headers/source 文件可以从中受益。看,
$ ./detect-musl.sh
-D__MUSL__ -D__MUSL_VER_MAJOR__=1 -D__MUSL_VER_MINOR__=1 -D__MUSL_VER_PATCH__=24
请尽早在您的 Makefile 中调用它并相应地调整您的 CFLAGS
。
此脚本执行 ldd
脚本,获取名称中包含 musl
的库,然后执行它。所有 libc 库都是可执行的(因为它们字面上包含 _start()
),甚至可以产生输出。通常,这是版本信息。例如,GNU 显示为:
$ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.3.0.
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
而且,musl 显示了这个:
$ /lib/ld-musl-x86_64.so.1
musl libc (x86_64)
Version 1.1.24
Dynamic Program Loader
Usage: /lib/ld-musl-x86_64.so.1 [options] [--] pathname [args]
我已经在 Alpine 和 Linux Mint 上测试了我的脚本,它似乎工作正常。
和你一样,我讨厌迂腐的意识形态阻碍实用性。如果您找到更好的解决方案,请随时向上 post 。 :)
编辑:在交叉编译的情况下,ldd
不起作用。在生成测试程序并读取其 ELF 链接然后检查其中是否包含 musl libc
字符串的过程中涉及一些额外的工作。有关详细信息,请参阅 GitHub 代码段。
我来晚了,但我在试图找到同一问题的答案时注意到了 musl libc 的一个特点(在我的例子中,就是 musl 没有实现 pthread_setname_np)。当定义 _GNU_SOURCE 时,它不会在 features.h 中定义 __USE_GNU,而是使用 _GNU_SOURCE 来保护 GNU 扩展。
所以这个过程应该可以创建一个 musl libc 宏(如果另一个 libc 实现具有相同的行为或者没有 libc 的人出于某种原因包含一个存根 features.h,它将产生误报;但是 Glibc, uClibc 和 bionic 都在 features.h 中定义了 __USE_GNU 或当定义 _GNU_SOURCE 时 features.h 包含的另一个 header)
所以这对我有用 rn:
#define _GNU_SOURCE
#include <features.h>
#ifndef __USE_GNU
#define __MUSL__
#endif
#undef _GNU_SOURCE /* don't contaminate other includes unnecessarily */
musl 团队声称不需要检测 musl libc 的方法,因为他们只实现了标准功能,没有需要检测的怪癖。
直到今天,这种说法很可能是正确的,但现在已不再正确。正常的功能检测不起作用,因为该功能存在但已损坏,我宁愿不探测它,因为我不想在编译时要求 root 并禁止交叉编译。该错误已通过最小化示例代码报告,维护人员根本不想修复它,也不会接受我的补丁。
我不会惩罚所有其他 libc,因为 musl 有一个损坏的功能。
按理说我想做
#if MUSL || APPLE
pid = fork();
#else
pid = vfork();
#endif
我已经有 #if APPLE
因为 Mac OSX 有一个不可信的 vfork()
.
告诉我 vfork()
不好是没有意义的。自 2008 年以来,情况发生了变化,无论涉及的复杂性如何,只要有可能,vfork()
都是更好的选择。一些来源:https://gist.github.com/nicowilliams/a8a07b0fc75df05f684c23c18d7db234
我想这有点晚了,但这里有一个解决方案:
#! /bin/sh
tmpf=/tmp/musl.log
# Detect Musl C library.
libc=$(ldd /bin/ls | grep 'musl' | head -1 | cut -d ' ' -f1)
if [ -z $libc ]; then
# This is not Musl.
rm -f ${tmpf}
exit 1
fi
$libc >${tmpf} 2>&1
vstr=$(cat ${tmpf} | grep "Version" | cut -d ' ' -f2)
v_major=$(echo $vstr | cut -d '.' -f1)
v_minor=$(echo $vstr | cut -d '.' -f2)
v_patch=$(echo $vstr | cut -d '.' -f3)
rm -f ${tmpf}
echo "-D__MUSL__ -D__MUSL_VER_MAJOR__=${v_major} -D__MUSL_VER_MINOR__=${v_minor} -D__MUSL_VER_PATCH__=${v_patch}"
这个 shell 脚本提取了一些有趣的信息并打印出 -D
友好的值,因此 headers/source 文件可以从中受益。看,
$ ./detect-musl.sh
-D__MUSL__ -D__MUSL_VER_MAJOR__=1 -D__MUSL_VER_MINOR__=1 -D__MUSL_VER_PATCH__=24
请尽早在您的 Makefile 中调用它并相应地调整您的 CFLAGS
。
此脚本执行 ldd
脚本,获取名称中包含 musl
的库,然后执行它。所有 libc 库都是可执行的(因为它们字面上包含 _start()
),甚至可以产生输出。通常,这是版本信息。例如,GNU 显示为:
$ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.3.0.
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
而且,musl 显示了这个:
$ /lib/ld-musl-x86_64.so.1
musl libc (x86_64)
Version 1.1.24
Dynamic Program Loader
Usage: /lib/ld-musl-x86_64.so.1 [options] [--] pathname [args]
我已经在 Alpine 和 Linux Mint 上测试了我的脚本,它似乎工作正常。
和你一样,我讨厌迂腐的意识形态阻碍实用性。如果您找到更好的解决方案,请随时向上 post 。 :)
编辑:在交叉编译的情况下,ldd
不起作用。在生成测试程序并读取其 ELF 链接然后检查其中是否包含 musl libc
字符串的过程中涉及一些额外的工作。有关详细信息,请参阅 GitHub 代码段。
我来晚了,但我在试图找到同一问题的答案时注意到了 musl libc 的一个特点(在我的例子中,就是 musl 没有实现 pthread_setname_np)。当定义 _GNU_SOURCE 时,它不会在 features.h 中定义 __USE_GNU,而是使用 _GNU_SOURCE 来保护 GNU 扩展。
所以这个过程应该可以创建一个 musl libc 宏(如果另一个 libc 实现具有相同的行为或者没有 libc 的人出于某种原因包含一个存根 features.h,它将产生误报;但是 Glibc, uClibc 和 bionic 都在 features.h 中定义了 __USE_GNU 或当定义 _GNU_SOURCE 时 features.h 包含的另一个 header)
所以这对我有用 rn:
#define _GNU_SOURCE
#include <features.h>
#ifndef __USE_GNU
#define __MUSL__
#endif
#undef _GNU_SOURCE /* don't contaminate other includes unnecessarily */