Pregunta

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 creando una biblioteca de objetos compartida en lugar de un archivo ejecutable, no aparecen errores al momento de compilar. Me he olvidado de implementar esa función. La única manera de descubrir que algo está mal es en el 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, tal vez algo que pueda agregar a mi Makefile.

Una solución que encontré es ejecutar la biblioteca compilada a través de nm -C -U para obtener una lista de todas las referencias indefinidas. El problema es que también aparece la lista de todas las referencias que se encuentran en otras bibliotecas, como GLibC, que, por supuesto, se vincularán junto con esta biblioteca cuando se reúna la aplicación final. Sería posible usar la salida de nm para grep a través de todos mis archivos de encabezado y ver si alguno de los nombres correspondientes ... pero esto parece una locura. Seguramente este no es un problema poco común y hay una mejor manera de resolverlo.

¿Fue útil?

Solución

Verifique la opción de vinculador -z defs / --no-undefined . Al crear un objeto compartido, hará que el enlace falle si hay símbolos sin resolver.

Si está utilizando gcc para invocar el vinculador, usará la opción del compilador -Wl para pasar la opción al vinculador:

gcc -shared ... -Wl,-z,defs

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 construyes en un objeto compartido, tendrá éxito:

> gcc -shared -fPIC -o libsilly.so silly.c && echo succeeded || echo failed
succeeded

Pero si agrega -z defs , el enlace fallará y le informará sobre el símbolo que falta:

> 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

Otros consejos

En Linux (que parece estar usando) ldd -r a.out debería darle exactamente la respuesta que está buscando.

ACTUALIZACIÓN: una forma trivial de crear a.out para verificar:

 echo "int main() { return 0; }" | g++ -xc++ - ./libMySharedLib.so
 ldd -r ./a.out

¿Qué pasa con un testuite? Crea simulacros ejecutables que enlazan con los símbolos que necesita. Si la vinculación falla, significa que la interfaz de su biblioteca está incompleta.

Una vez tuve el mismo problema. Estaba desarrollando un modelo de componente en C ++ y, por supuesto, los componentes deberían cargarse en tiempo de ejecución dinámicamente. Se me ocurren tres soluciones, que fueron las que apliqué:

  1. Tómese un tiempo para definir un sistema de compilación que sea capaz de compilar estáticamente. Perderá tiempo diseñándolo, pero le ahorrará mucho tiempo al detectar estos molestos errores de ejecución.
  2. Agrupe sus funciones en secciones bien conocidas y entendidas, de modo que pueda agrupar funciones / stubs para asegurarse de que cada función correspondiente tenga su stub. Si se toma el tiempo de documentarlo bien, puede escribir un script que verifique las definiciones (a través de, por ejemplo, sus comentarios de doxygen) y verifique el archivo .cpp correspondiente.
  3. Realice varios ejecutables de prueba que carguen el mismo conjunto de bibliotecas y especifique el indicador RTLD_NOW para dlopen (si está bajo * NIX). Ellos señalarán los símbolos que faltan.

Espero que ayude.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top