Estoy escribiendo una biblioteca de objetos compartidos de C ++ bastante grande y me he encontrado con un pequeño problema que hace que la depuración sea un problema:
Si defino una función / método en un archivo de encabezado y me olvido de crear un código auxiliar para él (durante el desarrollo), ya que estoy construyendo como una biblioteca de objetos compartidos en lugar de un ejecutable, no aparecen errores en tiempo de compilación que me digan que tengo olvidado implementar esa función. La única forma en que descubro que algo está mal es en tiempo de ejecución, cuando finalmente una aplicación que se vincula con esta biblioteca se cae con un error de "símbolo indefinido".
Estoy buscando una manera fácil de verificar si tengo todos los símbolos que necesito en el momento de la compilación, quizás algo que pueda agregar a mi Makefile.
Una solución que se me ocurrió es ejecutar la biblioteca compilada nm -C -U
para obtener una lista exigida de todas las referencias no definidas. El problema es que esto también aparece con la lista de todas las referencias que se encuentran en otras bibliotecas, como GLibC, que por supuesto se vinculará junto con esta biblioteca cuando se prepare la aplicación final. Sería posible utilizar la salida de a nm
a grep
través de todos mis archivos de encabezado y ver si alguno de los nombres corresponde ... pero esto parece una locura. Seguramente este no es un problema poco común y existe una mejor manera de resolverlo.
fuente
nm -C -u
me ha salvado varias veces! (tenga en cuenta las minúsculas-u
en mi sistema). Dejo este comentario aquí para poder encontrarlo la próxima vez que lo necesite.Respuestas:
Consulte la opción del enlazador
-z defs
/--no-undefined
. Al crear un objeto compartido, el enlace fallará si hay símbolos sin resolver.Si está utilizando gcc para invocar el enlazador, usará la
-Wl
opción del compilador para pasar la opción al enlazador:Como ejemplo, considere el siguiente archivo:
#include <stdio.h> void forgot_to_define(FILE *fp); void doit(const char *filename) { FILE *fp = fopen(filename, "r"); if (fp != NULL) { forgot_to_define(fp); fclose(fp); } }
Ahora, si lo integra en un objeto compartido, tendrá éxito:
Pero si agrega
-z defs
, el enlace fallará y le informará sobre su símbolo faltante:> gcc -shared -fPIC -o libsilly.so silly.c -Wl,-z,defs && echo succeeded || echo failed /tmp/cccIwwbn.o: In function `doit': silly.c:(.text+0x2c): undefined reference to `forgot_to_define' collect2: ld returned 1 exit status failed
fuente
-Bsymbolic
a la línea de comandos del vinculador. Incluso siforgot_to_define
ahora existe en la biblioteca gracias a la-z
verificación, el ejecutable aún puede anularlo con su propia definición y las propias definiciones de la biblioteca irán a esa anulación;-Bsymbolic
fuerza las cosas para que las propias definiciones de la biblioteca a sus funciones vayan a sus funciones.// forgot_to_define(fp);
, no informa un errorEn Linux (que parece estar usando)
ldd -r a.out
debería darle exactamente la respuesta que está buscando.ACTUALIZAR: una forma trivial de crear
a.out
contra la cual verificar:echo "int main() { return 0; }" | g++ -xc++ - ./libMySharedLib.so ldd -r ./a.out
fuente
¿Qué tal un testuite? Crea ejecutables simulados que se vinculan a los símbolos que necesita. Si el enlace falla, significa que la interfaz de su biblioteca está incompleta.
fuente
Tuve el mismo problema una vez. Estaba desarrollando un modelo de componentes en C ++ y, por supuesto, los componentes deberían cargarse en tiempo de ejecución de forma dinámica. Me vienen a la mente tres soluciones, que fueron las que apliqué:
Espero que ayude.
fuente