Измените версию разделяемой библиотеки Linux (.so) после ее компиляции

Я собираю библиотеки Linux (для Android, используя NDK g++, но я уверен, что мой вопрос имеет смысл для любой системы Linux). При доставке этих библиотек партнерам мне нужно отметить их номером версии. Я также должен иметь доступ к номер версии программно (чтобы показать его в диалоговом окне "О программе" или в функции GetVersion).

Сначала я скомпилировал библиотеки с неверсированным флагом (версия 0.0) и вам нужно изменить эту версию на реальную, когда я закончил тестирование перед отправкой его партнеру. Я знаю, что было бы легче изменить исходный код и перекомпилировать, но мы не хотим этого делать (потому что мы должны снова проверить все, если мы перекомпилируем код, мы чувствуем, что он будет меньше подвержен ошибкам, см. Комментарии к этому и, наконец, потому, что наша среда разработки работает следующим образом: мы выполняем этот процесс для двоичных файлов Windows: мы устанавливаем строку версии 0.0 ресурсов (.rc), а позже ее меняем с помощью verpatch... мы хотели бы работать с одним и тем же процессом при доставке Linux файлов).

Что было бы лучшей стратегией здесь? Подводя итог, требования следующие:

  • Скомпилировать двоичные файлы с "неустановленной" версией (0.0 или что-либо еще)
  • Можете изменить эту "неустановленную" версию на конкретную, не перекомпилируя двоичный файл (в идеале, запустите команду стороннего инструмента, как и при использовании verpatch в Windows)
  • Уметь иметь код библиотеки для получения информации о версии во время выполнения

Если ваш ответ "переименовать .so", то просьба предоставить решение для 3.: как получить имя версии (например, имя файла) во время выполнения.

Я думал о некоторых решениях, но понятия не имел, могут ли они работать и как их достичь.

  • У вас есть переменная версии (одна string или 3 int) в коде и есть способ изменить ее в двоичном файле позже? Использование двоичного sed...?
  • У вас есть переменная версии внутри ресурса и есть способ изменить ее в двоичном файле позже? (как мы это делаем для win32/win64)
  • Используйте поле .so(как SONAME), посвященное этому, и у вас есть инструмент, позволяющий изменить его... и сделать его доступным из кода на С++.
  • Переименуйте lib + change SONAME (не нашли, как это может быть достигнуто)... и найдите способ получить его из кода на С++.
  • ...

Обратите внимание, что мы используем QtCreator для компиляции файлов Android.so, но они не могут полагаться на Qt. Поэтому использование ресурсов Qt не является идеальным решением.

Ответы

Ответ 1

Обсуждение с Slava заставило меня понять, что любой const char* был фактически видимым в двоичном файле и затем может быть легко исправлен на что-либо еще.

Итак, вот хороший способ исправить мою собственную проблему:

  • Создайте библиотеку с:
    • определение const char version[] = "VERSIONSTRING:00000.00000.00000.00000"; (нам нужно это достаточно долго, так как мы можем впоследствии безопасно изменить содержимое двоичного файла, но не расширять его...)
    • a GetVersion, которая очистит переменную version выше (удалить VERSIONSTRING: и бесполезно 0). Он вернется:
      • 0.0, если version VERSIONSTRING:00000.00000.00000.00000
      • 2.3, если version есть VERSIONSTRING:00002.00003.00000.00000
      • 2.3.40, если version есть VERSIONSTRING:00002.00003.00040.00000
      • ...
  • Скомпилируйте библиотеку, назовите ее mylib.so
  • Загрузите его из программы, спросите его версию (вызов GetVersion), он возвращает 0.0, не удивительно.
  • Создайте небольшую программу (она была сделана на С++, но может быть выполнена на Python или любом другом языке), который будет:
    • загрузите весь файл двоичного файла в память (используя std::fstream с std::ios_base::binary)
    • найдите VERSIONSTRING:00000.00000.00000.00000 в нем
    • подтверждает, что он появляется только один раз (чтобы убедиться, что мы не модифицируем то, что мы не имели в виду, поэтому я префикс строки VERSIONSTRING, чтобы сделать ее более унифицированной...)
    • исправить его до VERSIONSTRING:00002.00003.00040.00000, если ожидаемое двоичное число 2.3.40
    • сохранить двоичный файл обратно из исправленного содержимого
  • Патч mylib.so с использованием вышеуказанного инструмента (например, запрашивающая версия 2.3)
  • Запустите ту же программу, что и в шаге 3. Теперь она сообщает 2.3!

Не перекомпиляция и не связывание, вы исправили двоичную версию!

Ответ 2

Я боюсь, что вы начали решать свою проблему с самого конца. Прежде всего, SONAME предоставляется во время ссылки в качестве параметра компоновщика, поэтому вначале вам нужно найти способ получить версию из источника и перейти к компоновщику. Одно из возможных решений - используйте утилиту ident и поставьте строку версии в своем двоичном формате, например:

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

эта строка должна появиться в двоичной и ident утилита обнаружит ее. Или вы можете самостоятельно анализировать исходный файл с помощью grep или чего-то подобного. Если есть вероятность конфликтов, добавьте дополнительный маркер, который вы можете использовать позже, чтобы обнаружить эту строку, например:

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

Таким образом, вы обнаруживаете номер версии либо из исходного файла, либо из файла .o и просто передаете его в компоновщик. Это должно работать.

Что касается версии для отладки версии 0.0, то это легко - просто избегайте обнаружения при создании отладки и просто используйте 0.0 как версию безоговорочно.

Для сторонней системы сборки я бы рекомендовал использовать cmake, но это только мои личные предпочтения. Решение может быть легко реализовано и в стандартном Makefile. Я не уверен в qmake, хотя.