summaryrefslogtreecommitdiffstats
path: root/api/src/README.Symbol_Versions
diff options
context:
space:
mode:
authorKaleb S. KEITHLEY <kkeithle@redhat.com>2014-11-18 11:08:16 -0500
committerShyamsundar Ranganathan <srangana@redhat.com>2015-01-12 09:16:08 -0800
commitc49a77001bd80affa70d22ba974d8de9e3f0f0cd (patch)
tree15cf68f9bbe72f3d4d00f5ae750e4d8ac980af36 /api/src/README.Symbol_Versions
parentf839e25a1ee67279c0c59da9d7262728133e8b37 (diff)
api: versioned symbols in libgfapi.so for compatibility
Use versioned symbols to keep libgfapi at libgfapi.so.0.0.0 Revisited to address broken build on Mac OS X See http://review.gluster.org/9036 Rebased to include http://review.gluster.org/#/c/9376/ (glfs_resolve()) but note that gerrit's "Rebase Change" couldn't do it. N.B. noticed that glfs_get_volumeid() decl in glfs.h was missing the __THROW, added it. On systems using ELF and the GNU toolchain, symbol versions are created with a .symver asm operand in the .c source file. Clang is claimed to be compatible with gcc, so we'll pretend for now that this also works with clang. On Mac OS X, aliases are created with __asm "magic" in the .h header file. In the normal case, when both the decl and defn match, that's all that's needed. In our case though the decl and defn don't match --- we have, e.g. a defn such as 'int glfs_foo(...)' and the corresponding decl is 'int pub_glfs_foo(...)'. To make this work we create the necessary aliases in the library at link time with the -alias_list link option. Note that this results in there being pairs of symbols in the .dylib, e.g. _pub_glfs_foo and _glfs_foo$GFAPI_3.4.0. We could use another link option, -unexported_symbols_list to elide the _pub_glfs_* symbols. (And we probably should.) Linux symbol versioning was essentially copied from Solaris; in general I would expect this to "just work" on Solaris, but until someone tries we don't really know. Change-Id: Icb96a3c2d80be7b6d7a6849bb9168f03a947f47c BUG: 1160709 Signed-off-by: Kaleb S. KEITHLEY <kkeithle@redhat.com> Reviewed-on: http://review.gluster.org/9143 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Niels de Vos <ndevos@redhat.com> Reviewed-by: Shyamsundar Ranganathan <srangana@redhat.com>
Diffstat (limited to 'api/src/README.Symbol_Versions')
-rw-r--r--api/src/README.Symbol_Versions228
1 files changed, 228 insertions, 0 deletions
diff --git a/api/src/README.Symbol_Versions b/api/src/README.Symbol_Versions
new file mode 100644
index 00000000000..d69c364bb07
--- /dev/null
+++ b/api/src/README.Symbol_Versions
@@ -0,0 +1,228 @@
+
+1. Symbol Versions and SO_NAMEs
+
+ In general, adding new APIs to a shared library does not require that
+symbol versions be used or the the SO_NAME be "bumped." These actions
+are usually reserved for when a major change is introduced, e.g. many
+APIs change or a signficant change in the functionality occurs.
+
+ Over the normal lifetime of a When a new API is added, the library is
+recompiled, consumers of the new API are able to do so, and existing,
+legacy consumers of the original API continue as before. If by some
+chance an old copy of the library is installed on a system, it's unlikely
+that most applications will be affected. New applications that use the
+new API will incur a run-time error terminate.
+
+ Bumping the SO_NAME, i.e. changing the shared lib's file name, e.g.
+from libfoo.so.0 to libfoo.so.1, which also changes the ELF SO_NAME
+attribute inside the file, works a little differently. libfoo.so.0
+contains only the old APIs. libfoo.so.1 contains both the old and new
+APIs. Legacy software that was linked with libfoo.so.0 continues to work
+as libfoo.so.0 is usually left installed on the system. New software that
+uses the new APIs is linked with libfoo.so.1, and works as long as
+long as libfoo.so.1 is installed on the system. Accidentally (re)installing
+libfoo.so.0 doesn't break new software as long as reinstalling doesn't
+erase libfoo.so.1.
+
+ Using symbol versions is somewhere in the middle. The shared library
+file remains libfoo.so.0 forever. Legacy APIs may or may not have an
+associated symbol version. New APIs may or may not have an associated
+symbol version either. In general symbol versions are reserved for APIs
+that have changed. Either the function's signature has changed, i.e. the
+return time or the number of paramaters, and/or the parameter types have
+changed. Another reason for using symbol versions on an API is when the
+behaviour or functionality of the API changes dramatically. As with a
+library that doesn't use versioned symbols, old and new applications
+either find or don't find the versioned symbols they need. If the versioned
+symbol doesn't exist in the installed library, the application incurs a
+run-time error and terminates.
+
+ GlusterFS wanted to keep tight control over the APIs in libgfapi.
+Originally bumping the SO_NAME was considered, and GlusterFS-3.6.0 was
+released with libgfapi.so.7. Not only was "7" a mistake (it should have
+been "6"), but it was quickly pointed out that many dependent packages
+that use libgfapi would be forced to be recompiled/relinked. Thus no
+packages of 3.6.0 were ever released and 3.6.1 was quickly released with
+libgfapi.so.0, but with symbol versions. There's no strong technical
+reason for either; the APIs have not changed, only new APIs have been
+added. It's merely being done in anticipation that some APIs might change
+sometime in the future.
+
+ Enough about that now, let's get into the nitty gritty——
+
+2. Adding new APIs
+
+2.1. Adding a public API.
+
+ This is the default, and the easiest thing to do. Public APIs have
+declarations in either glfs.h, glfs-handles.h, or, at your discretion,
+in a new header file intended for consumption by other developers.
+
+Here's what you need to do to add a new public API:
+
++ Write the declaration, e.g. in glfs.h:
+
+ int glfs_dtrt (const char *volname, void *stuff) __THROW
+
++ Write the definition, e.g. in glfs-dtrt.c:
+
+ int
+ pub_glfs_dtrt (const char *volname, void *stuff)
+ {
+ ...
+ return 0;
+ }
+
++ Add the symbol version magic for ELF, gnu toolchain to the definition.
+
+ following the definition of your new function in glfs-dtrtops.c, add a
+ line like this:
+
+ GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_dtrt, 3.7.0)
+
+ The whole thing should look like:
+
+ int
+ pub_glfs_dtrt (const char *volname, void *stuff)
+ {
+ ...
+ }
+ GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_dtrt, 3.7.0);
+
+ In this example, 3.7.0 refers to the Version the symbol will first
+ appear in. There's nothing magic about it, it's just a string token.
+ The current versions we have are 3.4.0, 3.4.2, 3.5.0, 3.5.1, and 3.6.0.
+ They are to be considered locked or closed. You can not, must not add
+ any new APIs and use these versions. Most new APIs will use 3.7.0. If
+ you add a new API appearing in 3.6.2 (and mainline) then you would use
+ 3.6.2.
+
++ Add the symbol version magic for OS X to the declaration.
+
+ following the declaration in glfs.h, add a line like this:
+
+ GFAPI_PUBLIC(glfs_dtrt, 3.7.0)
+
+ The whole thing should look like:
+
+ int glfs_dtrt (const char *volname, void *stuff) __THROW
+ GFAPI_PUBLIC(glfs_dtrt, 3.7.0);
+
+ The version here must match the version associated with the definition.
+
++ Add the new API to the ELF, gnu toolchain link map file, gfapi.map
+
+ Most new public APIs will probably be added to a new section that
+ looks like this:
+
+ GFAPI_3.7.0 {
+ global:
+ glfs_dtrt;
+ } GFAPI_PRIVATE_3.7.0;
+
+ if you're adding your new API to, e.g. 3.6.2, it'll look like this:
+
+ GFAPI_3.6.2 {
+ global:
+ glfs_dtrt;
+ } GFAPI_3.6.0;
+
+ and you must change the
+ GFAPI_PRIVATE_3.7.0 { ...} GFAPI_3.6.0;
+ section to:
+ GFAPI_PRIVATE_3.7.0 { ...} GFAPI_3.6.2;
+
++ Add the new API to the OS X alias list file, gfapi.aliases.
+
+ Most new APIs will use a line that looks like this:
+
+ _pub_glfs_dtrt _glfs_dtrt$GFAPI_3.7.0
+
+ if you're adding your new API to, e.g. 3.6.2, it'll look like this:
+
+ _pub_glfs_dtrt _glfs_dtrt$GFAPI_3.6.2
+
+And that's it.
+
+
+2.2. Adding a private API.
+
+ If you're thinking about adding a private API that isn't declared in
+one of the header files, then you should seriously rethink what you're
+doing and figure out how to put it in libglusterfs instead.
+
+If that hasn't convinced you, follow the instructions above, but use the
+_PRIVATE versions of macros, symbol versions, and aliases. If you're 1337
+enough to ignore this advice, then you're 1337 enough to figure out how
+to do it.
+
+
+3. Changing an API.
+
+3.1 Changing a public API.
+
+ There are two ways an API might change, 1) its signature has changed, or
+2) its new functionality or behavior is substantially different than the
+old. An APIs signature consists of the function return type, and the number
+and/or type of its parameters. E.g. the original API:
+
+ int glfs_dtrt (const char *volname, void *stuff);
+
+and the changed API:
+
+ void *glfs_dtrt (const char *volname, glfs_t *ctx, void *stuff);
+
+ One way to avoid a change like this, and which is preferable in many
+ways, is to leave the legacy glfs_dtrt() function alone, document it as
+deprecated, and simply add a new API, e.g. glfs_dtrt2(). Practically
+speaking, that's effectively what we'll be doing anyway, the difference
+is only that we'll use a versioned symbol to do it.
+
+ On the assumption that adding a new API is undesirable for some reason,
+perhaps the use of glfs_gnu() is just so pervasive that we really don't
+want to add glfs_gnu2().
+
++ change the declaration in glfs.h:
+
+ glfs_t *glfs_gnu (const char *volname, void *stuff) __THROW
+ GFAPI_PUBLIC(glfs_gnu, 3.7.0);
+
+Note that there is only the single, new declaration.
+
++ change the old definition of glfs_gnu() in glfs.c:
+
+ struct glfs *
+ pub_glfs_gnu340 (const char * volname)
+ {
+ ...
+ }
+ GFAPI_SYMVER_PUBLIC(glfs_gnu340, glfs_gnu, 3.4.0);
+
++ create the new definition of glfs_gnu in glfs.c:
+
+ struct glfs *
+ pub_glfs_gnu (const char * volname, void *stuff)
+ {
+ ...
+ }
+ GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_gnu, 3.7.0);
+
++ Add the new API to the ELF, gnu toolchain link map file, gfapi.map
+
+ GFAPI_3.7.0 {
+ global:
+ glfs_gnu;
+ } GFAPI_PRIVATE_3.7.0;
+
++ Update the OS X alias list file, gfapi.aliases, for both versions:
+
+Change the old line:
+ _pub_glfs_gnu _glfs_gnu$GFAPI_3.4.0
+to:
+ _pub_glfs_gnu340 _glfs_gnu$GFAPI_3.4.0
+
+Add a new line:
+ _pub_glfs_gnu _glfs_gnu$GFAPI_3.7.0
+
++ Lastly, change all gfapi internal calls glfs_gnu to the new API.
+