c++ linux g++ shared-libraries versioning

c++ - Cambiar la versión de la biblioteca compartida de Linux(archivo.so) después de compilarla



g++ shared-libraries (2)

Estoy compilando bibliotecas de Linux (para Android, utilizando g ++ de NDK, pero apuesto a que mi pregunta tiene sentido para cualquier sistema Linux). Al entregar esas bibliotecas a los socios, debo marcarlas con un número de versión. También debo poder acceder al número de versión programáticamente (para mostrarlo en un cuadro de diálogo "Acerca de" o en una función GetVersion , por ejemplo).

Primero compilo las bibliotecas con una marca no versionada (versión 0.0 ) y necesito cambiar esta versión a una real cuando termine de probar justo antes de enviarla al socio. Sé que sería más fácil modificar la fuente y la compilación, pero no queremos hacerlo (ya que deberíamos probar todo de nuevo si recompilamos el código, sentimos que sería menos propenso a errores, vea los comentarios a este publique y finalmente porque nuestro entorno de desarrollo funciona de esta manera: hacemos este proceso para binarios de Windows: establecemos una cadena de versión de recursos 0.0 (.rc) y luego la modificamos usando verpatch ... nos gustaría trabajar con la misma tipo de proceso al enviar binarios de Linux).

¿Cuál sería la mejor estrategia aquí? Para resumir, los requisitos son:

  1. Compilar binarios con la versión "unset" ( 0.0 o cualquier otra cosa)
  2. Poder modificar esta versión "sin establecer" a una específica sin tener que volver a compilar el binario (idealmente, ejecute un comando de herramienta de terceros, como lo hacemos con verpatch en Windows)
  3. Ser capaz de hacer que el código de la biblioteca recupere la información de su versión en tiempo de ejecución

Si su respuesta es "cambiar el nombre del archivo .so", proporcione una solución para 3 .: cómo recuperar el nombre de la versión (es decir, el nombre del archivo) en tiempo de ejecución.

Estaba pensando en algunas soluciones, pero no tengo idea de si podrían funcionar y cómo lograrlas.

  • ¿Tiene una variable de versión (una string o 3 int ) en el código y tiene una manera de cambiarla en el archivo binario más adelante? Usando un sed binario ...?
  • ¿Tiene una variable de versión dentro de un recurso y tiene una manera de cambiarla en el archivo binario más adelante? (como lo hacemos para win32 / win64)
  • Use un campo del .so (como SONAME) dedicado a esto y tenga una herramienta que le permita cambiarlo ... y hágalo accesible desde el código C ++.
  • Cambie el nombre de lib + change SONAME (no encontró cómo se puede lograr esto) ... y encuentre una manera de recuperarlo desde el código C ++.
  • ...

Tenga en cuenta que utilizamos QtCreator para compilar los archivos .so de Android, pero es posible que no se basen en Qt. Por lo tanto, usar los recursos de Qt no es una solución ideal.


La discusión con Slava me hizo darme cuenta de que cualquier const char* era realmente visible en el archivo binario y que luego podía parchearse fácilmente a cualquier otra cosa.

Así que aquí hay una buena manera de solucionar mi propio problema:

  1. Crea una biblioteca con:
    • una definición de const char version[] = "VERSIONSTRING:00000.00000.00000.00000"; (Lo necesitamos el tiempo suficiente, ya que luego podemos modificar de forma segura el contenido del archivo binario pero no extenderlo ...)
    • una función GetVersion que limpiaría la variable de version anterior (elimine VERSIONSTRING: y el inútil 0 ). Volvería
      • 0.0 si la version es VERSIONSTRING:00000.00000.00000.00000
      • 2.3 si la version es VERSIONSTRING:00002.00003.00000.00000
      • 2.3.40 si la version es VERSIONSTRING:00002.00003.00040.00000
      • ...
  2. Compila la biblioteca, llamémosla mylib.so
  3. Cárguelo desde un programa, pregunte su versión (llamada GetVersion ), devuelve 0.0 , no es de extrañar.
  4. Cree un pequeño programa (lo hizo en C ++, pero se podría hacer en Python o en cualquier otro idioma) que:
    • cargar un contenido de archivo binario completo en la memoria (usando std::fstream con std::ios_base::binary )
    • encuentra VERSIONSTRING:00000.00000.00000.00000 en ella
    • confirma que aparece una sola vez (para asegurarnos de que no modifiquemos algo a lo que no pretendíamos, por eso prefijo la cadena con VERSIONSTRING , para hacerlo más único ...)
    • VERSIONSTRING:00002.00003.00040.00000 a VERSIONSTRING:00002.00003.00040.00000 si el número binario esperado es 2.3.40
    • guardar el archivo binario de nuevo desde el contenido parcheado
  5. Parche mylib.so usando la herramienta anterior (solicitando la versión 2.3 por ejemplo)
  6. Ejecute el mismo programa que en el paso 3., ahora informa 2.3 !

Sin recompilación ni vinculación, parcheaste la versión binaria!


Me temo que empezaste a resolver tu problema desde el final. En primer lugar, SONAME se proporciona en el momento del enlace como un parámetro del vinculador, por lo que al principio debe encontrar una forma de obtener la versión de origen y pasarla al vinculador. Una de las posibles soluciones: use la utilidad de ident y suministre una cadena de versión en su binario, por ejemplo:

const char version[] = "$Revision:1.2$"

esta cadena debe aparecer en binario y la utilidad de ident lo detectará. O puede analizar el archivo fuente directamente con grep o algo parecido. Si existe la posibilidad de que los conflictos pongan un marcador adicional, que puede usar más adelante para detectar esta cadena, por ejemplo:

const char version[] = "VERSION_1.2_VERSION"

Entonces, usted detecta el número de versión del archivo fuente o del archivo .o y simplemente lo pasa al vinculador. Esto debería funcionar.

En cuanto a la versión de depuración, tener la versión 0.0 es fácil: simplemente evite la detección cuando cree la depuración y solo use 0.0 como versión incondicional.

Para el sistema de compilación de terceros, recomendaría usar cmake , pero esto es solo mi preferencia personal. La solución también se puede implementar fácilmente en Makefile estándar. Aunque no estoy seguro de qmake .