【问题标题】:How can I find the full file path given a library name like libfoo.so.1?如何在给定库名称(如 libfoo.so.1)的情况下找到完整文件路径?
【发布时间】:2012-10-20 08:38:29
【问题描述】:

如果不实现链接器或使用ldd,我如何才能找到库的完整路径? Linux 上是否有可用的标准库? (可能是 POSIX?)

在一个故意使用libGL.so.1的文件上使用lddgrep,它看起来像:

$ ldd /usr/bin/glxinfo | grep libGL
libGL.so.1 => /usr/lib/libGL.so.1 (0x00007f34ff796000)

给定库名称 libGL.so.1,如何找到完整路径 /usr/lib/libGL.so.1。最好接受查找 32 位和 64 位库的选项。如果没有库这样做,是否存在执行此操作的程序?像find-library-path libGL.so.1 这样的东西。 locate libGL.so.1 命令不算数。

如果它从该库执行代码,我不想实际使用 dlopen 或其他方式加载该库。

【问题讨论】:

标签: c linux linker


【解决方案1】:

使用ldconfig,这是管理链接空间的工具。

-p 标志可让您浏览所有可用的可链接库。

【讨论】:

  • 感谢您的回答,但-p 打印文件中的缓存条目,而不是当前状态(例如,$LD_LIBRARY_PATH 中的目录不受尊重)
  • @Lekensteyn 如果您想在 any 位置找到库而不依赖于任何实际用于管理库的机制,findlocate DB可能是您唯一的选择。正如您的问题所述,查看加载程序的源代码也可能是一种选择。
【解决方案2】:

扩展 Honky Tonk 的答案,命令 echo "$(ldconfig -p | grep libGL.so.1 | tr ' ' '\n' | grep /)" 将单独为您提供路径。

【讨论】:

    【解决方案3】:

    如果您不介意实际加载库并使用一些非标准但广泛可用的函数,则对库中的任何符号调用 dladdr 将返回包含已加载完整路径名的信息。

    【讨论】:

    • 我会看一下手册页,我还对问题添加了另一个要求:库不应执行正在检查的库的代码。编辑:看起来dladdr 不会帮助我,因为它首先需要dlopen
    • 好吧,你不能(可移植地)避免在加载的库中执行全局构造函数。可能有一些不可移植的黑客在构造函数运行之前取回控制权,使用库依赖项和构造函数运行的特定于实现的顺序从另一个库的构造函数调用_exit(从分叉的子进程执行所有这些操作)事先,但我认为这进入了牵强的黑客领域。理想情况下,dlopen 应该有一个 RTLD_NOEXEC 标志来防止库中的任何代码执行,这对像你这样的任务很有用。
    • 是的,那是一厢情愿。有一个 RTLD_NOLOAD,但是当之前没有加载库时它只返回 NULL。我认为甚至没有考虑到 32 位/64 位的可用解决方案(也就是说,没有构建旨在检查这一点的 32 位和 64 位程序)。
    • 好吧,还有一个丑陋的黑客——你可以派生一个子进程并ptrace它,并在第一个mmap系统调用时终止它。之前的open 调用应该为您提供路径名。 :-) 顺便说一下,为什么你需要知道路径名?我怀疑有更好的方法来做你想要实现的目标。
    • primus 拦截 GL 调用并将渲染与加速分开。这些库不必位于$LD_LIBRARY_PATH 中,因此我不能将libGL.so.1 传递给该程序中的dlopen 函数,因此我必须将绝对路径传递给库。在第二个程序中,我想查找问题中所述的库,以便将其传递给 primus 程序。
    【解决方案4】:

    对于具有 GNU libc 和 Python 的系统,以下是我找到的最接近的系统。它使用LD_DEBUG(在the man page of ld.so(8) 中描述)。

    LD_DEBUG=libs python3 -c "import ctypes; ctypes.CDLL('libssl.so.1.0.0')" 2>&1 | \
        grep -A 1000 "initialize program: python" | grep -A 3 "find library"
    

    输出(libssl.so.1.0.0)如下:

     15370: find library=libssl.so.1.0.0 [0]; searching
     15370:  search cache=/etc/ld.so.cache
     15370:   trying file=/lib/x86_64-linux-gnu/libssl.so.1.0.0
     15370: 
     15370: find library=libcrypto.so.1.0.0 [0]; searching
     15370:  search cache=/etc/ld.so.cache
     15370:   trying file=/lib/x86_64-linux-gnu/libcrypto.so.1.0.0
     15370: 
    

    【讨论】:

      【解决方案5】:

      我实现了这样一个脚本here

      #!/usr/bin/env python3
      
      """
      Like `type` but for libs.
      """
      
      import sys
      import os
      from argparse import ArgumentParser
      from glob import glob
      
      
      def parse_ld_conf_file(fn):
          paths = []
          for l in open(fn).read().splitlines():
              l = l.strip()
              if not l:
                  continue
              if l.startswith("#"):
                  continue
              if l.startswith("include "):
                  for sub_fn in glob(l[len("include "):]):
                      paths.extend(parse_ld_conf_file(sub_fn))
                  continue
              paths.append(l)
          return paths
      
      
      def get_ld_paths():
          # To be very correct, see man-page of ld.so.
          # And here: http://unix.stackexchange.com/questions/354295/what-is-the-default-value-of-ld-library-path/354296
          # Short version, not specific to an executable, in this order:
          # - LD_LIBRARY_PATH
          # - /etc/ld.so.cache (instead we will parse /etc/ld.so.conf)
          # - /lib, /usr/lib (or maybe /lib64, /usr/lib64)
          paths = []
          if "LD_LIBRARY_PATH" in os.environ:
              paths.extend(os.environ["LD_LIBRARY_PATH"].split(":"))
          paths.extend(parse_ld_conf_file("/etc/ld.so.conf"))
          paths.extend(["/lib", "/usr/lib", "/lib64", "/usr/lib64"])
          return paths
      
      
      def main():
          arg_parser = ArgumentParser()
          arg_parser.add_argument("lib")
          args = arg_parser.parse_args()
      
          paths = get_ld_paths()
          for p in paths:
              fn = "%s/%s" % (p, args.lib)
              if os.path.exists(fn):
                  print(fn)
                  return
      
          print("Did not found %r in %r." % (args.lib, paths), file=sys.stderr)
          sys.exit(1)
      
      
      if __name__ == "__main__":
          main()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-04
        • 1970-01-01
        • 2022-11-30
        • 2012-07-04
        相关资源
        最近更新 更多