#dlopen #后端 #包装器 #加载 #运行时 #机制 #首次

bin+lib dlwrap

dlopen 包装器代码生成器

8 个版本

0.3.4 2024 年 7 月 31 日
0.3.3 2024 年 7 月 8 日
0.3.1 2024 年 6 月 30 日
0.3.0 2024 年 5 月 27 日
0.1.1 2024 年 5 月 14 日

开发工具 中排名第 504

Download history 107/week @ 2024-05-05 161/week @ 2024-05-12 154/week @ 2024-05-19 164/week @ 2024-05-26 10/week @ 2024-06-02 2/week @ 2024-06-09 404/week @ 2024-06-30 130/week @ 2024-07-07 5/week @ 2024-07-14 289/week @ 2024-07-28 7/week @ 2024-08-04

每月下载量 302

Apache-2.0

24KB
453

dlwrap

Crates.io Version docs.rs

在创建支持多个后端(如 压缩加密等)的应用程序时,有时不希望一次性将所有支持的库链接到应用程序中。

使用 dlopen,可以在第一次调用库中的函数时延迟加载库。这种机制通常通过围绕库函数的包装器来实现,尽管编写包装器既繁琐又容易出错。

dlwrap 使应用程序实现此机制变得简单。

用法

让我们考虑一个假设的应用程序,它调用 ZSTD_versionNumberZSTD_versionString 来检索 ZSTD 库的运行时版本。

首先创建一个源文件 zstdver.c,内容如下:

#include "zstdwrap.h"
#include <stdio.h>

int
main (void)
{
  unsigned v1 = ZSTDWRAP_FUNC(ZSTD_versionNumber)();
  printf ("ZSTD_versionNumber: %u\n", v1);
  const char *v2 = ZSTDWRAP_FUNC(ZSTD_versionString)();
  printf ("ZSTD_versionString: %s\n", v2);
  return 0;
}

需要注意以下几点

  • 不是标准的 <zstd.h> 头文件,而是包含 "zstdwrap.h"
  • 使用 ZSTDWRAP_FUNC 宏包装函数符号

现在继续生成辅助文件

$ cargo install dlwrap
$ dlwrap --input /usr/include/zstd.h \
         --output-dir out \
         --clang-resource-dir "$(clang -print-resource-dir)" \
         --loader-basename zstdwrap \
         --symbol-regex "^ZSTD_(versionNumber|versionString)$" \
         --prefix zstdwrap \
         --include "<zstd.h>"

此命令将在 out/ 下创建 3 个文件:zstdwrap.czstdwrap.hzstdwrapfuncs.h

此时,应用程序可以编译为

$ gcc -pthread -I./out \
      -DZSTDWRAP_ENABLE_DLOPEN=1 \
      -DZSTDWRAP_SONAME='"libzstd.so.1"' \
      -DZSTDWRAP_ENABLE_PTHREAD=1 \
      -o zstdver examples/zstdver.c out/zstdwrap.c

生成的代码提供了一些配置宏

  • <LIBRARY_PREFIX>_ENABLE_DLOPEN 控制是否启用此 dlopen 机制。如果它未定义或为 0,则应用程序需要在构建时链接到所需的库(见下文)。这对于根据是否支持 dlopen 的平台条件化构建非常有用。

  • <LIBRARY_PREFIX>_SONAME指定了dlopen的第一个参数。如果它未定义,则不会自动加载库,应用程序需要调用<library_prefix>_ensure_library函数,该函数将库SONAME作为第一个参数。这在应用程序在运行时确定实际库时很有用。

  • <LIBRARY_PREFIX>_ENABLE_PTHREAD控制自动库加载是否应为线程安全;在这种情况下,使用pthread_once来保护库加载和符号解析。

使用ldd检查zstdver可执行文件时,您会看到libzstd.so.1没有链接,但它似乎已经链接了。

$ ldd zstdver
        linux-vdso.so.1 (0x00007ffc705bf000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f8a1199f000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f8a11ba3000)

$ ./zstdver
ZSTD_versionNumber: 10506
ZSTD_versionString: 1.5.6

$ ltrace -e dlopen ./zstdver
zstdver->dlopen("libzstd.so.1", 1)               = 0x13152c0
ZSTD_versionNumber: 10506
ZSTD_versionString: 1.5.6
+++ exited (status 0) +++

未定义ZSTDWRAP_ENABLE_DLOPEN,相同的应用程序代码可以用标准链接方式编译(即在构建时链接libzstd)。

$ gcc -I./out \
      -o zstdver examples/zstdver.c out/zstdwrap.c \
      -lzstd

$ ldd ./zstdver
        linux-vdso.so.1 (0x00007ffcd43e4000)
        libzstd.so.1 => /lib64/libzstd.so.1 (0x00007f7323269000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f7323087000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f732334a000)

$ ltrace -e dlopen ./zstdver
ZSTD_versionNumber: 10506
ZSTD_versionString: 1.5.6
+++ exited (status 0) +++

许可协议

Apache-2.0

生成的代码可以在FSFAP下分发。

依赖关系

~4–5.5MB
~97K SLoC