Как сохранить номер версии в статической библиотеке?

Как я могу сохранить номер версии в статической библиотеке (file.a) и позже проверить его версию в Linux?

P.S. Мне нужна возможность проверить версию файла в любое время без использования какого-либо специального исполняемого файла только с помощью утилит оболочки.


person Pirks    schedule 28.10.2009    source источник
comment
Приведенные ниже решения (два, как я пишу), конечно же, доступны и для разделяемых библиотек.   -  person Jonathan Leffler    schedule 28.10.2009
comment
Просто добавил еще один ответ на основе вашего редактирования ... Надеюсь, что это поможет.   -  person jheddings    schedule 28.10.2009


Ответы (5)


Возможно, вы могли бы создать строку с такой версией:

char* library_version = { "Version: 1.3.6" };

и чтобы иметь возможность проверить это из оболочки, просто используйте:

strings library.a | grep Version | cut -d " " -f 2
person Puppe    schedule 28.10.2009
comment
Вы бы, конечно, сделали это const char library_version[] = "1.3.6";, чтобы сэкономить место для указателя. И вы должны объявить переменную в заголовке библиотеки (или в заголовке, распространяемом с библиотекой). - person Jonathan Leffler; 28.10.2009
comment
Добавлена ​​информация для проверки версии из оболочки - person Puppe; 28.10.2009

В дополнение к предоставлению статической строки, как упомянуто Puppe, обычной практикой является предоставление макроса для получения проверки версии на совместимость. Например, у вас могут быть следующие макросы (объявленные в файле заголовка для использования с вашей библиотекой):

#define MYLIB_MAJOR_VERSION 1
#define MYLIB_MINOR_VERSION 2
#define MYLIB_REVISION 3
#define MYLIB_VERSION "1.2.3"
#define MYLIB_VERSION_CHECK(maj, min) ((maj==MYLIB_MAJOR_VERSION) && (min<=MYLIB_MINOR_VERSION))

Обратите внимание на макрос MYLIB_CHECK_VERSION, я предполагаю, что вы хотите, чтобы конкретная основная версия и дополнительная версия были больше или равны вашей желаемой версии. Измените, как требуется для вашего приложения.

Затем используйте его из вызывающего приложения, например:

if (! MYLIB_VERSION_CHECK(1, 2)) {
    fprintf(stderr, "ERROR: incompatible library version\n");
    exit(-1);
}

Этот подход приведет к тому, что информация о версии будет поступать из включенного файла заголовка. Кроме того, он будет оптимизирован во время компиляции для вызывающего приложения. Немного поработав, вы можете извлечь его из самой библиотеки. Читать дальше...

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

struct {
    const char* string;
    const unsigned major;
    const unsigned minor;
    const unsigned revision;
} mylib_version = {
    MYLIB_VERSION, MYLIB_MAJOR_VERSION, MYLIB_MINOR_VERSION, MYLIB_REVISION
};

Это создаст в вашей библиотеке структуру с именем mylib_version. Вы можете использовать это для дальнейших проверок путем создания функций внутри вашей библиотеки и доступа к ним из вызывающего приложения и т. Д.

person jheddings    schedule 28.10.2009
comment
Единственная проблема с MYLIB_VERSION_CHECK, которую я вижу, заключается в том, что она оценивается во время компиляции, и хороший оптимизатор удалит проверку, если все в порядке, и безоговорочно вызовет printf () - вы имели в виду fprintf (stderr, ...) не так ли? - и выйти (). Я думаю, что было бы лучше вызвать функцию, которая встраивала бы логику, а не использовать постоянное выражение. - person Jonathan Leffler; 28.10.2009
comment
Да, хорошие моменты здесь ... Позже я отредактировал свой пост, чтобы включить встраивание информации в библиотеку по этой причине. Спасибо за разъяснения. - person jheddings; 28.10.2009

Создание нового ответа на основе вашего редактирования ... Просто чтобы избежать путаницы :)

Если вы ищете способ решения проблемы, не связанный с кодом, вы можете попробовать это. Это (еще раз) альтернатива подходу strings, определенному Puppe.

Может быть, вы могли бы просто прикоснуться к файлу с именем version_1.2.3 и добавить его в архив. Затем вы можете определить версию, выполнив поиск файла версии с помощью команды ar:

ar t libmylib.a | grep 'version_' | sed -e 's/^version_//'

Я не уверен, что это даст вам то, что вам нужно, но не существует стандартного метода для встраивания таких метаданных в архив. Возможно, вы найдете другую информацию, которую хотите сохранить в этом «метафайле» архива.

person jheddings    schedule 28.10.2009
comment
@ vitaly.v.ch Недоступно ни на чем, кроме linyux. - person MarcusJ; 02.06.2017
comment
@MarcusJ - это просто кросс-компиляция идентификатора для всего - person vitaly.v.ch; 02.06.2017
comment
Не curr. вы просто передали сложность из наших рук третьим лицам и добавили зависимость в процессе. Я рад, что это сработало для вас, но вы не знаете, если думаете, что это решение применимо ко всем. - person MarcusJ; 02.06.2017

Если вы используете gcc, вы можете использовать директиву #ident

#ident "Foo Version 1.2.3.4"
void foo(void){ /* foo code here */ }

Чтобы получить версию, просто используйте одно из следующего:

strings -a foo.o | grep "Foo Version"
strings -a foo.a | grep "Foo Version"
strings -a foo.so | grep "Foo Version"

Это позволит вам скомпилировать версию в библиотеку с возможностью впоследствии удалить ее с помощью strip -R .comment your_file или полностью опустить, передав -fno-ident (при этом также будут пропущены комментарии версии компилятора из скомпилированных объектов)

person technosaurus    schedule 02.06.2016

Несколько раз упоминалось man 1 ident, поэтому вот подробности об использовании этого метода.

ident - это команда, которая поставляется с RCS (системой контроля версий), но также может быть доступна, если вы используете CVS (система одновременных версий) или Subversion.

Вы бы использовали это так (клонировано со страницы руководства):

#include <stdio.h>
static char const rcsid[] =
    "$Id: f.c,v 5.4 1993/11/09 17:40:15 eggert Exp $";
int main() { return printf("%s\n", rcsid) == EOF; }

и f.c компилируется в f.o, тогда команда

ident f.c f.o

выведет

   f.c:
       $Id: f.c,v 5.4 1993/11/09 17:40:15 eggert Exp $
   f.o:
       $Id: f.c,v 5.4 1993/11/09 17:40:15 eggert Exp $

Если ваш f.o был добавлен в статическую библиотеку f.a, тогда ident f.a должен показать аналогичный результат. Если у вас есть несколько похожих [a-z].o в вашем az.a, вы должны найти все их строки в az.a файле.

ПРЕДОСТЕРЕЖЕНИЕ: То, что они находятся в файле .a, не означает, что они будут включены в ваш программный файл. Если программа не ссылается на них, компоновщик не видит необходимости включать их. Таким образом, у вас обычно должен быть метод в каждом модуле для возврата строки, и приложение должно вызывать этот метод. Есть способы убедить большинство компоновщиков в том, что это обязательный символ, без фактической ссылки на него, но это зависит от компоновщика и выходит за рамки этого ответа.

Если вместо этого вы знакомы с SCCS (системой управления исходным кодом), вы должны использовать вместо этого man 1 what, и это будет выглядеть следующим образом (сделано с помощью макросов, чтобы показать доступную гибкость):

#include <stdio.h>
#define VERSION_STR "5.4"
#define CONFIG "EXP"
#define AUTHOR "eggert"
static char const sccsid[] =
    "@(#) " CONFIG " v " VERSION_STR " " __DATE__ " " __TIME__ " " AUTHOR;
int main() { return printf("%s\n", sccsid) == EOF; }

и f.c компилируется в f.o, тогда команда

what f.c f.o

выведет

   f.c:
       @(#) EXP v 5.4 1993/11/09 17:40:15 eggert
   f.o:
       @(#) EXP v 5.4 1993/11/09 17:40:15 eggert

PS: и ident, и what - это команды, которые поставляются с конкретными централизованными системами управления версиями. Если вы используете распределенную систему управления версиями (например, git), вся концепция может не иметь смысла. Некоторые идеи по использованию git см. В этой ветке: Переход с CVS на git: $ Id: $ эквивалент?, хотя хэш не совпадает с номером версии. :)

person Jesse Chisholm    schedule 02.06.2016