在C中运行时检测库功能

Ser*_* L. 5 c lazy-loading shared-libraries ld

我正在尝试在C中构建一个程序,它具有许多依赖于各种共享库的可选功能.

在我们的异构计算集群中,并非所有这些库都可在所有系统上使用(或更新).

实例是从较新的glibc(符号sched_getcpu@@GLIBC_2.6,__sched_cpucount@@GLIBC_2.6)或整个共享库其可以是或可以不是可用的(libnuma,libR,libpbs).

我知道,我可以使用libdl与加载符号dlopendlsym,但这样做的(目前约为30)数量不断增长的符号是乏味的最好的.

据我所知,Linux中的共享库默认是延迟加载的,因此在实际使用之前不应该使用符号.

但是如果我尝试提前检查它,那么它在执行开始时失败:

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <dlfcn.h>
#include <sched.h>

int main() {

    void *lib_handle;
    int (*fn)(void);
    int x;
    char *error;

    lib_handle = dlopen("libc.so.6", RTLD_LAZY);
    if (!lib_handle) 
    {
       fprintf(stderr, "%s\n", dlerror());
       exit(1);
    }

    fn = dlsym(lib_handle, "sched_getcpu");
    if ((error = dlerror()) != NULL)  
    {
       fprintf(stderr, "%s\n", error);
       exit(1);
    }

    printf("%d\n", sched_getcpu());

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在包含所有库的编译系统上:

$ icc test.c
$ ./a.out
10
Run Code Online (Sandbox Code Playgroud)

在另一个具有较新版本的GLIBC的系统上:

$ ./a.out 
./a.out: /lib64/libc.so.6: version `GLIBC_2.6' not found (required by ./a.out)
Run Code Online (Sandbox Code Playgroud)

如果我注释掉实际调用的行,sched_getcpu那么我会改为使用较小的系统:

$ ./a.out 
/lib64/libc.so.6: undefined symbol: sched_getcpu
Run Code Online (Sandbox Code Playgroud)

那么,有没有办法强制库只在使用时加载,并在使用它们的块之前进行类似的检查?

Nik*_* C. 1

不适合 glibc。这是一个自动保险装置,它安装到位,这样您就不会搬起石头砸自己的脚。如果GLIBC_2.6未定义并查找该符号,即使没有其他丢失的符号,您也可能会从 glibc 获得垃圾结果(数据损坏和崩溃),因为它不向前兼容。

如果您需要 glibc 级别的兼容性,则需要针对最低的通用版本进行构建。