2009-10-28 16 views
7

Jak mogę zapisać numer wersji w bibliotece statycznej (plik.a), a następnie sprawdzić jego wersję w systemie Linux?Jak zapisać numer wersji w bibliotece statycznej?

P.S. Potrzebuję możliwości sprawdzenia wersji pliku w dowolnym momencie bez specjalnego pliku wykonywalnego, który jest używany tylko przez narzędzia powłoki.

+0

Rozwiązania poniżej (dwie, jak piszę) są oczywiście również dostępne dla bibliotek współdzielonych. –

+0

Po prostu dodałem kolejną odpowiedź na podstawie Twojej edycji ... Mam nadzieję, że pomaga. – jheddings

Odpowiedz

8

Być może można utworzyć ciąg z wersji jak ta:

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

i być w stanie sprawdzić go z powłoki wystarczy użyć:

strings library.a | grep Version | cut -d " " -f 2 
+0

Oczywiście, sprawisz, że 'const char library_version [] =" 1.3.6 ";' zapisze miejsce na wskaźnik. I zadeklarowałbyś zmienną w nagłówku biblioteki (lub w nagłówku dystrybuowanym z biblioteką). –

+0

proszę sprawdzić ponownie moje pytanie - został on zaktualizowany – Pirks

+1

Dodano informację dla sprawdzenia wersji z powłoki – Puppe

8

Ponadto, aby zapewnić stały ciąg znaków jak wspomina Puppe, powszechną praktyką jest dostarczanie makra do pobierania sprawdzania wersji pod kątem zgodności. Na przykład można mieć następujące makra (zadeklarowane w pliku nagłówka do użycia z biblioteki):

#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)) 

Wskazówka z MYLIB_CHECK_VERSION makro, jestem przy założeniu chcesz konkretnego główną rev i drobny rev większa lub równa żądanej wersji. Zmień zgodnie z wymaganiami dla aplikacji.

Następnie użyj go od wywołującego aplikacji, coś takiego:

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

Takie podejście powoduje, że informacje o wersji pochodzić z dołączonego pliku nagłówka. Dodatkowo zostanie zoptymalizowany podczas kompilacji aplikacji wywołującej. Przy odrobinie więcej pracy możesz wyodrębnić ją z samej biblioteki. Czytaj dalej ...

Możesz również użyć tych informacji, aby utworzyć statyczny ciąg przechowywany wewnątrz biblioteki, jak wspomniał Puppe. Umieścić coś takiego w twojej bibliotece:

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 
}; 

Spowoduje to utworzenie struct nazywa mylib_version w swojej bibliotece. Można to wykorzystać, aby zrobić kolejne weryfikacje poprzez tworzenie funkcji wewnątrz biblioteki i uzyskiwania dostępu do tych z wywołującego aplikacji itp

+1

Jedyny problem z MYLIB_VERSION_CHECK, który widzę, to to, że jest on oceniany podczas kompilacji, a dobry optymalizator usunie test, jeśli wszystko będzie w porządku, i bezwarunkowo wywoła printf() - chodziło ci o fprintf (stderr, ...), prawda? - i exit(). Myślę, że lepiej byłoby wywołać funkcję, która wbudowała logikę zamiast używać stałego wyrażenia. –

+0

Taaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Dziękuję za wyjaśnienie. – jheddings

+0

proszę ponownie sprawdzić moje pytanie - zostało zaktualizowane – Pirks

3

Tworzenie nowej odpowiedzi na podstawie edycję ... Wystarczy, aby uniknąć nieporozumień :)

Jeśli szukasz niekodowanego sposobu rozwiązania problemu, możesz spróbować tego. Jest to (jeszcze raz) alternatywa dla podejścia zdefiniowanego przez Puppe'a.

Może wystarczy dotknąć pliku o nazwie version_1.2.3 i dodać go do archiwum. Następnie można określić wersję szukając wersji pliku za pomocą polecenia AR:

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

Nie jestem pewien, czy to będzie Ci to, czego potrzebujesz, ale nie ma standardowej metody osadzania metadane tak w archiwum. Może znajdziesz inne informacje, które chcesz zapisać w tym "metapliku" do archiwum.

+0

Co powiesz na ** 'man 1 ident' **? –

+0

Ta metoda nie jest odpowiednia do kontroli wersji. –

+0

@ vitaly.v.ch Niedostępne w przypadku niczego oprócz przewodów zwrotnych. – MarcusJ

0

Kilka razy wymieniono man 1 ident, więc tutaj są szczegóły dotyczące korzystania z tej metody.

ident to polecenie dołączone do RCS (Revision Control System), ale może być również dostępne, jeśli używasz CVS (Concurrent Versions System) lub Subversion.

będzie go używać tak (sklonowana ze strony człowieka):

#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; } 

FC jest kompilowany na fo, wówczas polecenia

ident f.c f.o 

wyjściowy będzie

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 $ 

Jeśli twoje f.o zostały dodane do biblioteki statycznej f.a, to ident f.a powinien pokazywać podobne wyjście. Jeśli masz kilka podobnie zbudowanych [a-z].o w twoim az.a, powinieneś znaleźć wszystkie ich ciągi w pliku az.a.

CAVEAT: Tylko dlatego, że znajdują się w pliku .a nie oznacza, że ​​będą one zawarte w pliku programu. Jeśli program nie odwołuje się do nich, linker nie widzi potrzeby ich uwzględniania. Więc zwykle musisz mieć metodę w każdym module, aby zwrócić ciąg znaków, a aplikacja musi wywołać tę metodę. Istnieją sposoby, aby przekonać większość linkerów, że jest to wymagany symbol bez faktycznego odwoływania się do niego, ale zależy to od linkera i wykracza poza zakres tej odpowiedzi.

Jeśli zamiast tego są zaznajomieni z SCCS (Źródło Code Control System), wówczas należałoby użyć man 1 what zamiast, i będzie to wyglądać tak (wykonane z makrami pokazać elastyczność dostępne):

#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; } 

i fc wkompilowany fo, wówczas polecenie

what f.c f.o 

wyjściowy będzie

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: zarówno ident, jak i what są komendami, które pochodzą z określonych scentralizowanych systemów kontroli źródła. Jeśli używasz rozproszonego systemu kontroli źródła (takiego jak git), cała koncepcja może nie mieć sensu. W przypadku niektórych pomysłów z użyciem git zobacz ten wątek: Moving from CVS to git: $Id:$ equivalent? chociaż hash nie jest taki sam jak numer wersji. :)

0

Jeśli używasz gcc, można użyć dyrektywy #ident

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

Aby uzyskać wersję wystarczy użyć jednego z następujących czynności:

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

Pozwoli to skompilować wersja do biblioteki z możliwością późniejszego rozebrania go za pomocą strip -R .comment your_file lub całkowite pominięcie go przez przekazanie -fno-ident (Pominie to również komentarze do wersji kompilatora ze skompilowanych obiektów)

Powiązane problemy