c++ - from - makefile linux c
Vinculación con múltiples versiones de una biblioteca (3)
Gracias por todas las respuestas. Tengo una solución que parece estar funcionando. Aquí está el problema en detalle con un ejemplo.
En main.c tenemos:
#include <stdio.h>
extern int foo();
int bar()
{
printf("bar in main.c called/n");
return 0;
}
int main()
{
printf("result from foo is %d/n", foo());
printf("result from bar is %d/n", bar());
}
En foo.c tenemos:
extern int bar();
int foo()
{
int x = bar();
return x;
}
En bar.c tenemos:
#include <stdio.h>
int bar()
{
printf("bar in bar.c called/n");
return 2;
}
Compilar bar.c y foo.c:
$ gcc -fPIC -c bar.c
$ gcc -fPIC -c foo.c
Agregue bar.o a una biblioteca estática:
$ ar r libbar.a bar.o
Ahora crea una biblioteca compartida usando foo.o y vincula con estática libbar.a
$ gcc -shared -o libfoo.so foo.o -L. -lbar
Compilar main.c y enlazar con la biblioteca compartida libfoo.so
$ gcc -o main main.c -L. -lfoo
Configure LD_LIBRARY_PATH para encontrar libfoo.so y ejecute main:
$ setenv LD_LIBRARY_PATH `pwd`
$ ./main
bar in main.c called
result from foo is 0
bar in main.c called
result from bar is 0
Observe que se llama a la versión de barra en main.c, no a la versión vinculada a la biblioteca compartida.
En main2.c tenemos:
#include <stdio.h>
#include <dlfcn.h>
int bar()
{
printf("bar in main2.c called/n");
return 0;
}
int main()
{
int x;
int (*foo)();
void *handle = dlopen("libfoo.so", RTLD_GLOBAL|RTLD_LAZY);
foo = dlsym(handle, "foo");
printf("result from foo is %d/n", foo());
printf("result from bar is %d/n", bar());
}
Compile y ejecute main2.c (aviso que no necesitamos vincular explícitamente con libfoo.so):
$ gcc -o main2 main2.c -ldl
$ ./main2
bar in bar.c called
result from foo is 2
bar in main2.c called
result from bar is 0
Ahora foo en la barra de llamadas de la biblioteca compartida en la biblioteca compartida y en la barra de llamadas principal en main.c
No creo que este comportamiento sea intuitivo y es más trabajo usar dlopen / dlsym, pero resuelve mi problema.
Nuevamente, muchas gracias por los comentarios.
Tengo una aplicación que enlaza estáticamente con la versión X de una biblioteca, libfoo, de un proveedor de terceros, VENDOR1. También se vincula con una biblioteca dinámica (compartida), libbar, de un proveedor de terceros diferente, VENDOR2, que vincula estáticamente la versión Y de libfoo de VENDOR1.
Por lo tanto, libbar.so contiene la versión Y de libfoo.a y mi ejecutable contiene la versión X de libfoo.a libbar solo usa libfoo internamente y no hay objetos libfoo pasados de mi aplicación a libbar.
No hay errores en el momento de la construcción, pero en el tiempo de ejecución, la aplicación falla. La razón parece ser que la versión X usa estructuras que tienen un tamaño diferente a la versión Y y el enlazador de tiempo de ejecución parece estar mezclando las que se usan para cada una.
Tanto VENDOR1 como VENDOR2 son de código cerrado, por lo que no puedo reconstruirlos.
¿Hay alguna forma de crear / enlazar mi aplicación de manera que siempre se resuelva a la versión X y libbar siempre se resuelva a la versión Y y las dos nunca se mezclen?
Lo siento, no. Mi comprensión de la forma en que Linux (y posiblemente la mayoría de los * nixes) es que eso no es posible. La única ''solución'' para su problema que se me ocurre es si crea una aplicación proxy, que expone lo que necesita de libbar en forma de algún IPC . Luego puedes hacer que el proxy cargue la versión correcta usando LD_LIBRARY_PATH
o algo similar.
Pruebe un enlace parcial para tener un archivo de objeto "partial.o" con libbar y libfoo-Y. Use objcopy con "--localize-symbols" para hacer que los símbolos en partial.o de libfoo-Y sean locales. Debería poder generar ejecutando nm en libfoo-Y y dando masajes a la salida. Luego, toma el partial.o modificado y vincúlalo a tu aplicación
He hecho algo similar con gcc toolchain en vxWorks, donde las libretas dinámicas no son una complicación, pero se necesitan dos versiones de la misma libreta para vincularse limpiamente en una aplicación monolítica.