Pokud mohou být dva balíčky nainstalovány souběžně, nesmí mít společné názvy souborů a lidé provádějící vývoj vůči balíčku vždy kompilují vůči očekávané verzi. Pro démony, pomocné programy a konfigurační soubory to platí úplně stejně, jako pro hlavičkové soubory a binární knihovny.
Zajistěte, aby všechny verze knihoven šly nainstalovat vedle sebe. ()
Všem souborům instalovaným knihovnou přidělte číslo verze. ()
Udržujte číslo verze balíčku oddělené od názvu souboru s knihovnou nebo čísla verze libtool. Je pak jasnější, která část čísla verze balíčku se mění s API. ()
Nainstalujte hlavičkové soubory C do
Nainstalujte spustitelné soubory knihovny do
Nainstalujte soubory pkg-config do
U souborů s nastavením zajistěte zpětnou a dopřednou kompatibilitu nebo je instalujte do
Nastavte GETTEXT_PACKAGE
na library-version
. ()
Do všech názvů rozhraní D-Bus, názvů služeb a cest k objektům zahrňte číslo verze. Například: org.domain.KnihovnaVerze.Rozhraní
, org.domain.KnihovnaVerze
a /org/domain/KnihovnaVerze/
. ()
Nainstalujte spustitelné soubory démonů do
Spustitelné soubory pomůcek instalujte do
Všechny veřejné knihovny by měly být navržené tak, aby je šlo instalovat souběžně ve více verzích, kvůli jednoduššímu pozdějšímu porušení API po dobu existence knihovny. Pokud je knihovna používána více projekty a chcete porušit API, buď musí projekty naráz přejít na nové API, nebo některé z nich již nebude nadále možné nainstalovat souběžně s ostatními, protože závisí na konfliktní verzi této knihovny.
To komplikuje správu a žádat pro všech projektech, aby naráz přesly na novou verzi API je organizačně náročné a demoralizující, protože většina porušení API nepřinese mnoho nových funkcí, které by motivovaly k přechodu.
Řešením je zajistit, aby šly všechny verze knihoven nainstalovat naráz, takže staré i nové verze API budou nainstalované a aplikace zkompilované vůči nim souběžně, bez konfliktů. Vestavění podpory pro tento druh souběžné instalace je mnohem jednodušší udělat na začátku projektu, než to dělat zpětně.
Tím se odstraní problém „slepice nebo vejce“ při přechodu celé sady aplikací z jedné verze knihovny na novější a pro správce knihovny si tím velmi zjednoduší porušení API, takže mohou při vývoji mnohem rychleji reagovat na přání nových funkcí.
Jiným a rovněž platným řešením pro knihovny je, nikdy nenarušovat API — tímto se řídí libc
.
Řešením problému v podstatě je přejmenovat knihovnu a ve většině případů je nejhezčím způsobem, jak to udělat, vložit do cesty ke každému instalovanému souboru číslo verze. Díky tomu může být naráz nainstalováno více verzí knihovny.
Kupříkladu řekněme, že knihovna Foo
tradičně instaluje tyto soubory:
Můžete změnit verzi 4 knihovny Foo
, aby místo toho instalovala tyto soubory:
Pak by mohly být nainstalovány souběžně s verzí 5:
To je jednoduše podporováno pomocí
Číslo verze které se zahrne do názvu souboru je veze ABI/API. Nemělo by jít o celé číslo verze balíčku, jen o část, která významěmně porušuje API. Pokud používáte pro číslování verzí projektu standartní schéma hlavní.vedlejší.setinkové
, je verzí API typicky hlavní číslo verze.
Vedlejší vydání (typicky, když je přidáno API, ale není změněno nebo odebráno) a setinková vydání (typicky opravy chyb) neovlivňují zpětnou kompatibilitu API, takže nevyžadují přesun všech souborů.
Příklady v následujícím oddíle předpokládají, že verze API a název souboru s knihovnou jsou exportovány z
# Před vydáním by se měl upravit řetězec KNIHOVNA_LT_VERSION, který
# je ve formě a:r:v (aktuální:revize:věk). Postupujte podle následujících bodů:
#
# 1. Když od poslední aktualizace došlo ke změně zdrojového kódu knihovny
# jako celku, zvyšte revizi („a:r:v“ se změní na „a:r+1:v“).
# 2. Když bylo od poslední aktualizace přidáno, odebráno nebo změněno
# rozhraní, zvyšte aktuální a revizi nastavte na 0.
# 3. Když bylo od posledního veřejného vydání přidáno rozhraní, zvyšte věk.
# 4. Když bylo od posledního veřejného vydání odebráno nebo změněno
# rozhraní, nastavte věk na 0.
AC_SUBST([KNIHOVNA_LT_VERSION],[1:0:0])
AC_SUBST([KNIHOVNA_API_VERSION],[4])
Hlavičkové soubory by vždy měly být nainstalovány v podsložce s číslem verze, kterou požaduje přepínač
#include <foo/foo.h>
pak by měly být nainstalovány tyto soubory:
Aplikace by měla kompilátoru jazyka C předat přepínač
Všimněte si zvláštní podsložky #include
, aby se předešlo kolizi názvů s jinými knihovnami. Když například dvě různé knihovny nainstalují každá hlavičkový soubor s názvem #include <utils.h>
?
Existuje pokušení ponechat jeden z hlavičkových souborů mimo kteroukoliv podsložku:
Problém je v tom, že uživatel určitě vždycky omylem použije nesprávnou hlavičku, protože
Hlavičkové soubory s číslem verze mohou být instalovány z automake pomocí následujícího kódu:
libraryincludedir = $(includedir)/liblibrary-@LIBRARY_API_VERSION@/library
library_headers = \
liblibrary/example1.h \
liblibrary/example2.h \
$(NULL)
# The following headers are private, and shouldn't be installed:
private_headers = \
liblibrary/example-private.h \
$(NULL)
# The main header simply #includes all other public headers:
main_header = liblibrary/library.h
public_headers = \
$(main_header) \
$(library_headers) \
$(NULL)
libraryinclude_HEADERS = $(public_headers)
Kromě správného číslování verzí by měla mít všechna API v instalovaných hlavičkových souborech správný jmenný prostor.
Objektové soubory knihovny by měly mít názvy s číslem verze. Například:
To umožňuje aplikacím získat při kompilaci právě tu, kterou chtějí a zajistí to, že verze 4 a 5 nemají žádné soubory společné.
Knihovny s číslem verze mohou být sestaveny a nainstalovány z automake pomocí následujícího kódu:
lib_LTLIBRARIES = libknihovna/libknihovna-@KNIHOVNA_API_VERSION@.la
libknihovna_libknihovna_@KNIHOVNA_API_VERSION@_la_SOURCES = \
$(private_headers) \
$(knihovna_sources) \
$(NULL)
libknihovna_libknihovna_@KNIHOVNA_API_VERSION@_la_CPPFLAGS = …
libknihovna_libknihovna_@KNIHOVNA_API_VERSION@_la_CFLAGS = …
libknihovna_libknihovna_@KNIHOVNA_API_VERSION@_la_LIBADD = …
libknihovna_libknihovna_@KNIHOVNA_API_VERSION@_la_LDFLAGS = \
-version-info $(KNIHOVNA_LT_VERSION) \
$(AM_LDFLAGS) \
$(NULL)
Názvy souborů s knihovnami (známé též jako soname nebo číslování verzí libtool) se zaměřují jen na problém linkování dříve přeložených aplikací za běhu. Neřeší záležitosti okolo kompilace aplikací, které požadují dřívější verzi, a ani nic jiného okolo knihoven.
Z toho důvodu byste ještě navíc měli používat pro knihovny názvy s číslováním verzi. Každá z těchto věcí cílí na jiný problém.
Soubory pkg-config by měly mít názvy s číslem verze. Například:
Protože každý soubor pkg-config obsahuje informace o verzi názvu knihovny včetně cesty, měl by být kterýkoliv projekt, který závisí na knihovně, schopen se přepnout z jedné verze na jinou prostou změnou kontroly ve svém pkg-config z
Soubory pkg-config s rozlišením verze mohou být instalovány z autoconf a automake pomocí následujícího kódu:
AC_CONFIG_FILES([
libknihovna/knihovna-$KNIHOVNA_API_VERSION.pc:libknihovna/knihovna.pc.in
],[],
[KNIHOVNA_API_VERSION='$KNIHOVNA_API_VERSION'])
# Všimněte si, že soubor s šablonou se nazývá library.pc.in, ale generuje se
# soubor .pc s číslem verze pomocí stejné magie, jako v AC_CONFIG_FILES.
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libknihovna/knihovna-$(KNIHOVNA_API_VERSION).pc
DISTCLEANFILES += $(pkgconfig_DATA)
EXTRA_DIST += libknihovna/knihovna.pc.in
Z hlediska uživatele je nejlepším přístupem k souborům s nastavením udržovat formát dopředně i zpětně kompatibilní (obě verze knihovny rozumí právě té stejné syntaxi a sémantice souboru s nastavením). Pak lze použít ten samý soubor s nastavením pro všechny verze knihovny a není potřeba žádné číslování verzí u souborů s nastavením.
Pokud to ale dodržet nejde, měly by být soubory s nastavením jednoduše přejmenovány a uživatel musí nastavit každou verzi knihovny zvlášť.
Jestli používáte pro překlady gettext v kombinaci s autoconf a automake, je normální postup nainstalovat překlady do
GETTEXT_PACKAGE=foo-4
AC_SUBST([GETTEXT_PACKAGE])
AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE],["$GETTEXT_PACKAGE"])
Pak použijte GETTEXT_PACKAGE
jako název balíčku předaný do bindtextdomain()
, textdomain()
a dgettext()
.
Rozhraní D-Bus je další formou API a podobá se API v C s tím rozdílem, že rozlišení verze se neprovádí při kompilaci, ale za běhu. Číslování verzí rozhraní D-Bus se jinak od API v C nijak neliší: čísla verzí musí být zahrnuta v názvech rozhraní, názvech služeb a v cestách k objektům.
Například pro službu org.example.Foo
vystavující rozhraní A
a B
na objektech Controller
a Client
, by verze 4 a 5 API pro D-Bus vypadala nějak takto:
org.example.Foo4
org.example.Foo5
org.example.Foo4.InterfaceA
org.example.Foo4.InterfaceB
org.example.Foo5.InterfaceA
org.example.Foo5.InterfaceB
/org/example/Foo4/Controller
/org/example/Foo4/Client
/org/example/Foo5/Controller
/org/example/Foo5/Client
Grafické aplikace obecně nepotřebují být nainstalované ve více verzích, protože na nich nezávisí další moduly. Démoni a pomocné programy ale spolupracují s dalšími částmi systému, a tak číslování verzí v názvech potřebují.
Mějme démona a pomocný program:
Číslo verze pak mohou mít přidělené jako:
Můžete nainstalovat symbolický odkaz z