2012-12-18 19 views
5

Ich versuche, ein Programm in C zu erstellen, das viele optionale Funktionen enthält, die von verschiedenen gemeinsam genutzten Bibliotheken abhängen.Erkennen von Bibliotheksfunktionen zur Laufzeit in C

In unserem heterogenen Computercluster sind nicht alle diese Bibliotheken auf allen Systemen verfügbar (oder aktuell).

Beispiele sind Symbole von neuer glibc ([email protected]@GLIBC_2.6, [email protected]@GLIBC_2.6) oder ganzem Shared Libraries, die nicht verfügbar sind oder nicht (libnuma, libR, libpbs).

Ich weiß, dass ich libdl kann die Symbole mit dlopen und dlsym, zu laden, aber für eine stetig wachsende Anzahl von Symbolen dies zu tun (rund 30 im Moment) ist bestenfalls langweilig.

Soweit ich weiß Shared Libraries in Linux sind standardmäßig Lazy-geladen, so dass ein Symbol nicht benötigt werden, bis es tatsächlich verwendet wird.

Aber wenn ich versuche, für die im Voraus zu überprüfen, dann scheitert es bei Ausführungsbeginn:

#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; 
} 

Auf der Kompilierung-System, das alle Bibliotheken hat:

$ icc test.c 
$ ./a.out 
10 

Auf einem anderen System, das eine weniger hat Aktuelle Version von GLIBC:

Wenn ich die Zeile auskommentieren, die tatsächlichaufruftdann bekomme ich stattdessen auf das kleinere System:

$ ./a.out 
/lib64/libc.so.6: undefined symbol: sched_getcpu 

So ist es eine Möglichkeit, Bibliotheken zu zwingen, nur auf den Einsatz und haben Kontrollen wie diese vor Blöcke, die sie verwenden geladen werden?

+0

Es könnte auf lange Sicht sicherer sein, Ihren Cluster ein wenig homogener zu machen. Alternativ dazu ist es die beste Lösung, alle Ihre ausführbaren Dateien, die auf diesen inkonsistent gepflegten Systemen ausgeführt werden müssen, statisch zu verknüpfen und zu hoffen, dass zumindest anständig kompatible Kernel ausgeführt werden. Wenn Ihr Cluster eine BSD ausführt, NetBSD wäre dann einfach, vorausgesetzt, Sie haben die App mit der ältesten Version des Systems verbunden, das im Cluster läuft. –

+0

@ GregA.Woods Das erzähle ich meinen Systemadministratoren. Aber das Problem ist: Ich bin ein Softwareentwickler. Ich muss Code schreiben und es laufen lassen. Ich habe nicht einmal Admin-Zugriff auf den Cluster, also ist das keine Option. Kernel sind alles Linux, aber es ist eine Mischung aus CentOS in verschiedenen Geschmacksrichtungen auf den Low-Power-Maschinen und RedHat auf den Supercomputern. –

+0

Dann statische Verbindung ist Ihre beste und vielleicht einzige Option. Sie müssen möglicherweise Ihre eigene Build-Maschine erstellen, um eine Kernel-Version mit dem kleinsten gemeinsamen Nenner zu finden. Für die meisten Dinge ist es auch nicht so schwer. –

Antwort

1

Nicht mit glibc. Dies ist ein Fail-Safe und es ist an Ort und Stelle, so dass Sie sich nicht in den Fuß schießen. Wenn das Symbol GLIBC_2.6 nicht definiert und nachgeschlagen wurde, könnten Sie, selbst wenn keine anderen fehlenden Symbole vorhanden waren, Garbage-Ergebnisse von glibc (Datenbeschädigung und Abstürze) erhalten, da es nicht vorwärtskompatibel ist.

Wenn Sie Kompatibilität auf der Glibc-Ebene benötigen, müssen Sie gegen die niedrigste gemeinsame Version bauen.

+0

OK, also muss ich glibc Symbole manuell laden oder 'syscall' direkt benutzen. Im Moment bin ich nur mit den beiden aufgelisteten Symbolen nicht kompatibel. Was ist mit anderen Bibliotheken? –

+0

@SergeyL. Andere Bibliotheken arbeiten wie gewohnt. Wenn die Definitionen der von Ihnen bereitgestellten Symbole kompatibel sind, funktionieren sie. –

Verwandte Themen