操作系统环境:Ubuntu 22.04
在安装一个工具应用时,这个应用使用到了chacha20加密算法,所以需要依赖libsodium。按照网上教程下载源码并编译安装:
sudo apt install build-essential
wget https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz
tar xf libsodium-1.0.18.tar.gz
cd libsodium-1.0.18
./configure
make
sudo make install
ldconfig
当启动该工具应用时出现报错:
File "/home/ubuntu/.local/lib/python3.7/site-packages/*****/crypto/util.py", line 80, in find_library
path = ctypes.util.find_library(name)
File "/usr/lib/python3.7/ctypes/util.py", line 341, in find_library
_get_soname(_findLib_gcc(name)) or _get_soname(_findLib_ld(name))
File "/usr/lib/python3.7/ctypes/util.py", line 147, in _findLib_gcc
if not _is_elf(file):
File "/usr/lib/python3.7/ctypes/util.py", line 99, in _is_elf
with open(filename, 'br') as thefile:
FileNotFoundError: [Errno 2] No such file or directory: b'liblibsodium.a'
首先确认了libsodium的安装过程,整个安装步骤没有报错,根据安装日志,也在/usr/local/lib/下找到了libsodium.a文件。
网上搜索这个问题,遇到同一问题的人很少,但是却有很多人遇到另一个库"liblibc.a"的报错,他们的解决方案是在libc.a的同一目录下建立软连接liblibc.a,抱着试一试的心态,我在/usr/local/lib下建立了一个软连接
cd /usr/local/lib
sudo ln -s libsodium.a liblibsodium.a
这时候再运行应用,果然运行正常。
根据报错日志
File "/usr/lib/python3.7/ctypes/util.py", line 341, in find_library
_get_soname(_findLib_gcc(name)) or _get_soname(_findLib_ld(name))
File "/usr/lib/python3.7/ctypes/util.py", line 147, in _findLib_gcc
if not _is_elf(file):
File "/usr/lib/python3.7/ctypes/util.py", line 99, in _is_elf
with open(filename, 'br') as thefile:
我们从下往上,定位是在哪一步添加了多出来的lib前缀。
通过分析源码,我们可以发现
elif os.name == "posix":
# Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
import re, tempfile
........
def _findLib_gcc(name):
# Run GCC's linker with the -t (aka --trace) option and examine the
# library name it prints out. The GCC command will fail because we
# haven't supplied a proper program with main(), but that does not
# matter.
expr = os.fsencode(r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name))
........
res = re.findall(expr, trace)
if not res:
return None
for file in res:
# Check if the given file is an elf file: gcc can report
# some files that are linker scripts and not actual
# shared objects. See bpo-41976 for more details
if not _is_elf(file):
continue
return os.fsdecode(file)
在报错日志中调用的_findLib_gcc方法中,是通过正则表达式来查找库文件的,而这里的正则表达式:
expr = os.fsencode(r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name))
已经自动在库名称前添加了lib前缀。同样的根据python官方文档
ctypes.util.find_library(name)
Try to find a library and return a pathname. name is the library name without any prefix like lib, suffix like .so, .dylib or version number (this is the form used for the posix linker option -l). If no library can be found, returns None.
The exact functionality is system dependent.
要求name中是不能含有lib前缀的。所以这时候我们要检查应用在调用find_library(name)时,传入的name是否含有额外的lib前缀了。
查看find_library的调用源码
def find_library(possible_lib_names, search_symbol, library_name,
custom_path=None):
import ctypes.util
........
lib_names = []
for lib_name in possible_lib_names:
lib_names.append(lib_name)
lib_names.append('lib' + lib_name)
for name in lib_names:
if os.name == "nt":
paths.extend(find_library_nt(name))
else:
path = ctypes.util.find_library(name)
if path:
paths.append(path)
果然是有一个加lib前缀的操作
lib_names.append('lib' + lib_name)
我们只要注释掉这行代码问题就能解决了。所以这是一个find_library调用不规范引起的报错。
有的电脑上不会发生这个问题,因为还有一个逻辑间接导致的问题的出现,我这台电脑正好是多重因素赶上了。
即使加了多余的前缀lib,在执行re.findall(expr, trace)方法,大部分电脑返回的结果应该是空,但是我这台电脑trace里正巧有个报错信息,含有liblibsodium字段,导致正则表达式匹配出来的结果不为空,才会导致后续的打开文件失败。
b'/usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o\n
/usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/crti.o\n
/usr/lib/gcc/x86_64-linux-gnu/11/crtbeginS.o\n
/usr/bin/ld: cannot find -llibsodium: No such file or directory\n
/usr/bin/ld: note to link with /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libsodium.a use -l:libsodium.a or rename it to liblibsodium.a\n
/usr/lib/gcc/x86_64-linux-gnu/11/libgcc.a\n
/usr/lib/gcc/x86_64-linux-gnu/11/libgcc_s.so\n
/usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libgcc_s.so.1\n
/usr/lib/gcc/x86_64-linux-gnu/11/libgcc.a\n
collect2: error: ld returned 1 exit status\n'
参考:
ctypes.util.find_library(“libc”) fails
re — Regular expression operations