Измените версию разделяемой библиотеки 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
, хотя.