当前位置: 首页 > 工具软件 > libsodium > 使用案例 >

libsodium引用报错FileNotFoundError: [Errno 2] No such file or directory: b‘liblibsodium.a‘

洪和风
2023-12-01

问题

操作系统环境: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

 类似资料: