在 Ubuntu 22.04.3 WSL 实例中,我正在编译一个链接到
libuv
的共享库。
Ubuntu 22.04.3 WSL,直接来自 Microsoft Store,不包含
libuv
。通过 apt
包管理器安装它会在 /usr/lib/x86_64-linux-gnu/libuv.so
: 安装版本 1.43.0-1
$ find /usr -name libuv.so 2>/dev/null
$
$ sudo apt-get install -y libuv1-dev
# ...
$ find /usr -name libuv.so 2>/dev/null
/usr/lib/x86_64-linux-gnu/libuv.so
$
$ apt list | grep libuv1
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
libuv1-dev/jammy,now 1.43.0-1 amd64 [installed]
libuv1/jammy,now 1.43.0-1 amd64 [installed,automatic]
$
共享库的代码是一个较大项目的简化/MCVE。它需要版本 1.43.0-1 中不可用的
libuv
符号(特别是 uv_timespec64_t
和函数 uv_clock_gettime
)。因此,我安装了包含这些符号的较新版本。由于 apt
包管理器没有可用的新版本,因此我按照其 README.md 中的构建/安装说明进行操作。请注意,这似乎是在 /usr/local/lib/libuv.so
安装新版本,即它不会覆盖使用 apt-get
包管理器安装的版本:
$ git clone https://github.com/libuv/libuv.git && cd libuv && git checkout v1.45.0 && mkdir -p build && (cd build && cmake .. -DBUILD_TESTING=ON) && cmake --build build && (cd build && ctest -C Debug --output-on-failure) && sudo cmake --install build
# ...
$
$ find /usr -name libuv.so 2>/dev/null
/usr/lib/x86_64-linux-gnu/libuv.so
/usr/local/lib/libuv.so
$
现在,我的 Ubuntu WSL 实例中有两个版本的
libuv
:版本 1.43.0-1(位于 /usr/lib/x86_64-linux-gnu/libuv.so
)和版本 1.45.0(位于 /usr/local/lib/libuv.so
)。
这是我正在编译的共享库:
#include <uv.h>
int func() {
uv_timespec64_t now;
uv_close(NULL, NULL);
uv_clock_gettime(UV_CLOCK_REALTIME, &now);
return 0;
}
我编译如下:
$ cc --version && cc -fpic -ggdb -Wall -c -o func.o func.c
cc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Copyright (C) 2021 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.
$ cc -shared -o libfunc.so func.o -fpic -ggdb -luv
$
ldd
报告的共享库依赖关系如下。请注意,它链接到版本 1.43.0-1,位于 /usr/lib/x86_64-linux-gnu/libuv.so
(/lib
是到 /usr/lib
的符号链接):
$ ldd ./libfunc.so
linux-vdso.so.1 (0x00007ffc74bdb000)
libuv.so.1 => /lib/x86_64-linux-gnu/libuv.so.1 (0x00007f323f071000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f323ee49000)
/lib64/ld-linux-x86-64.so.2 (0x00007f323f0b1000)
$
$ ls -ld /lib
lrwxrwxrwx 1 root root 7 Nov 22 13:36 /lib -> usr/lib
$
但是,如果我关闭 (
wsl --shutdown
) 并重新启动我的 Ubuntu WSL 实例,那么无需(故意)更改环境或接触已编译的共享库,ldd
现在报告它链接到版本 1.45.0,位于在 /usr/local/lib/libuv.so
:
$ # I've started this new Ubuntu WSL instance after shutting down the last instance with `wsl --shutdown`
$
$ ldd ./libfunc.so
linux-vdso.so.1 (0x00007ffdd655d000)
libuv.so.1 => /usr/local/lib/libuv.so.1 (0x00007fe8db267000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe8db03f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe8db2b8000)
$
我的问题是:为什么“选择”链接的
libuv
在 WSL 实例关闭/重新启动后会发生变化?
这是 WSL 特定的吗?每个新实例都会在环境中调整某些内容(以及调整的“内容”是什么)?或者在物理关闭/重新启动后我会在任何 Linux PC 上观察到类似的行为吗?
从如何打印ld(链接器)搜索路径,我知道如何查询链接器的有序搜索路径:
$ ld --verbose | grep SEARCH_DIR | tr -s ' ;' \\012
SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu")
SEARCH_DIR("=/lib/x86_64-linux-gnu")
SEARCH_DIR("=/usr/lib/x86_64-linux-gnu")
SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64")
SEARCH_DIR("=/usr/local/lib64")
SEARCH_DIR("=/lib64")
SEARCH_DIR("=/usr/lib64")
SEARCH_DIR("=/usr/local/lib")
SEARCH_DIR("=/lib")
SEARCH_DIR("=/usr/lib")
SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64")
SEARCH_DIR("=/usr/x86_64-linux-gnu/lib")
...这意味着链接器更喜欢
/lib/x86_64-linux-gnu/libuv.so.1
(如前所述,链接到/usr/lib/x86_64-linux-gnu/libuv.so.1
)而不是/usr/local/lib/libuv.so.1
。这解释了 ldd
的关闭前输出,但没有解释 ldd
的重启后输出。
我知道的另一件可能相关的事情是
/etc/ld.so.conf
和/etc/ld.so.conf.d/
。但是,关闭/重新启动 Ubuntu WSL 实例后,/etc/ld.so.conf
或 /etc/ld.so.conf.d/
中的任何文件都没有更改。
由于 apt 包管理器没有可用的新版本,因此我按照 README.md 中的构建/安装说明进行操作。请注意,这似乎是在
安装新版本。/usr/local/lib/libuv.so
这是一个非常糟糕的主意(TM)。
可以下载1.43源码包,查看配置情况;然后以同样的方式配置1.45。这应该会导致将二进制文件放入同一位置。然而,这也是一个坏主意,因为它会搞乱包管理器和依赖项,迟早会导致系统损坏。 更好的想法是配置非默认包并将其安装到非默认位置,例如
./configure --prefix /usr/local/libuv-1.45
。
该库将不会被随机构建使用;您必须专门指出它才能使用它。通常你会使用类似的东西:
make LVTOP=/usr/local/libuv-1.45 CFLAGS='-I${LVTOP}/include' \
LDFLAGS='-L${LVTOP}/lib -rpath=${LVTOP}/lib'
指示编译器使用
${LVTOP}/include
作为标头,链接器使用
${LVTOP}/lib
进行静态 (ld
) 和动态 (ld-linux.so
) 链接。
以这种方式使用时,额外的软件包不会以任何方式干扰系统,不会影响您的其他构建,并且不会在重新启动时神奇地更改配置。附注这并没有直接回答“为什么重新启动会改变某些东西?”的问题,但请参阅上面的评论以了解我对为什么会发生这种情况的最佳猜测。