todas rotas rota problemas paquete las kali instalar dependencias dependencia deepin como c++ linux linker ld circular-dependency

c++ - rotas - ¿Resolviendo dependencias circulares uniendo la misma biblioteca dos veces?



instalar dependencias kali linux (3)

Tenemos una base de código dividida en bibliotecas estáticas. Desafortunadamente, las bibliotecas tienen dependencias circulares; Por ejemplo, libfoo.a depende de libbar.a y viceversa.

Sé que la forma "correcta" de manejar esto es usar las opciones --start-group y --end-group del enlazador, de esta manera:

g++ -o myApp -Wl,--start-group -lfoo -lbar -Wl,--end-group

Pero en nuestros Makefiles existentes, el problema se maneja así:

g++ -o myApp -lfoo -lbar -lfoo

(Imagine esto extendido a ~ 20 bibliotecas con interdependencias complejas).

He estado revisando nuestros Makefiles cambiando la segunda forma a la primera, pero ahora mis compañeros de trabajo me preguntan por qué ... Y aparte de "porque está más limpio" y tiene la vaga sensación de que la otra forma es peligrosa, no lo hago. tener una buena respuesta

Entonces, ¿vincular la misma biblioteca varias veces puede crear un problema? Por ejemplo, ¿podría el enlace fallar con símbolos definidos múltiples si el mismo .o se inserta dos veces? ¿O existe algún riesgo de que podamos terminar con dos copias del mismo objeto estático, creando errores sutiles?

Básicamente, quiero saber si existe alguna posibilidad de fallas en el tiempo de enlace o en el tiempo de ejecución al vincular la misma biblioteca varias veces; Y si es así, cómo activarlos. Gracias.


Dado que es una aplicación heredada, apuesto a que la estructura de las bibliotecas se hereda de una disposición que probablemente ya no importa, como el uso de otro producto que ya no se usa.

Incluso si aún existen razones estructurales para la estructura de la biblioteca heredada, es casi seguro que aún sería aceptable construir una biblioteca más a partir de la disposición anterior. Simplemente coloque todos los módulos de las 20 bibliotecas en una nueva biblioteca, liballofthem.a . Entonces, cada aplicación es simplemente g++ -o myApp -lallofthem ...


El problema con

g++ -o myApp -lfoo -lbar -lfoo

es que no hay garantía, que dos pasadas sobre libfoo y una pasada sobre libbar son suficientes.

El enfoque con Wl,--start-group ... -Wl,--end-group es mejor, porque es más robusto.

Considere el siguiente escenario (todos los símbolos están en diferentes archivos de objetos):

  • myApp necesita el símbolo fooA definido en libfoo .
  • El símbolo fooA necesita el símbolo barB definido en libbar .
  • Symbol barB necesita el símbolo fooC definido en libfoo . Esta es la dependencia circular, que puede ser manejada por -lfoo -lbar -lfoo .
  • El símbolo fooC necesita el símbolo barD definido en libbar .

Para poder construir en el caso anterior, deberíamos pasar -lfoo -lbar -lfoo -lbar al vinculador. ¿Por qué?

  1. El enlazador ve libfoo por primera vez y usa definiciones del símbolo fooA pero no fooC , porque hasta el momento no ve la necesidad de incluir también fooC en el binario. Sin embargo, el enlazador comienza a buscar la definición de barB , porque su definición es necesaria para que fooA funcione.
  2. El enlazador ve -libbar , incluye la definición de barB (pero no barD ) y comienza a buscar la definición de fooC .
  3. La definición de fooC se encuentra en libfoo , cuando se procesó por segunda vez. Ahora se hace evidente que también se necesita la definición de barD , ¡pero demasiado tarde ya no hay un libbar en la línea de comandos!

El ejemplo anterior se puede extender a una profundidad de dependencia arbitraria (pero esto ocurre raramente en la vida real).

Así usando

g++ -o myApp -Wl,--start-group -lfoo -lbar -Wl,--end-group

es un enfoque más robusto, ya que el vinculador pasa con tanta frecuencia sobre el grupo de bibliotecas como sea necesario, solo cuando una pasada no cambió la tabla de símbolos el vinculador pasará a la siguiente biblioteca en la línea de comandos.

Sin embargo, hay una pequeña penalización de rendimiento que pagar: en el primer ejemplo, se analizó -lbar una vez más en comparación con la línea de comando manual -lfoo -lbar -lfoo . No estoy seguro de si vale la pena mencionar / pensar a través de.


Todo lo que puedo ofrecer es una falta de contra-ejemplo. De hecho, nunca he visto la primera forma antes (aunque es claramente mejor) y siempre he visto esto resuelto con la segunda forma, y ​​como resultado no he observado problemas.

Aun así, sugeriría cambiar a la primera forma porque muestra claramente la relación entre las bibliotecas en lugar de confiar en que el vinculador se comporte de una manera particular.

Dicho esto, sugeriría al menos considerar si existe la posibilidad de refactorizar el código para extraer las piezas comunes en bibliotecas adicionales.