15e5c12b0Sopenharmony_ci-------------------
25e5c12b0Sopenharmony_ciWritten by Ted T'so
35e5c12b0Sopenharmony_ci-------------------
45e5c12b0Sopenharmony_ci
55e5c12b0Sopenharmony_ci> https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
65e5c12b0Sopenharmony_ci>
75e5c12b0Sopenharmony_ci> I understood that, if there is no interface change but some implementation
85e5c12b0Sopenharmony_ci> changes, I need to bump revision. If new interface is added, for example, I
95e5c12b0Sopenharmony_ci> need to bump current while revision=0 and age++.
105e5c12b0Sopenharmony_ci
115e5c12b0Sopenharmony_ciSo part of the problem here is that libtool is doing something really
125e5c12b0Sopenharmony_cistrange because they are trying to use some abstract concept that is
135e5c12b0Sopenharmony_ciOS-independent.  I don't use libtool because I find it horribly
145e5c12b0Sopenharmony_cicomplex and doesn't add enough value to be worth the complexity.
155e5c12b0Sopenharmony_ci
165e5c12b0Sopenharmony_ciSo I'll tell you how things work with respect to Linux's ELF version
175e5c12b0Sopenharmony_cinumbering system.  Translating this to libtool's wierd "current,
185e5c12b0Sopenharmony_cirevision, age" terminology is left as an exercise to the reader.  I've
195e5c12b0Sopenharmony_cilooked at the libtool documentation, and it confuses me horribly.
205e5c12b0Sopenharmony_ciReading it, I suspect it's wrong, but I don't have the time to
215e5c12b0Sopenharmony_ciexperiment to confirm that the documentation is wrong and how it
225e5c12b0Sopenharmony_cidiverges from the libtool implementation.
235e5c12b0Sopenharmony_ci
245e5c12b0Sopenharmony_ciSo let me explain things using the ELF shared library terminology,
255e5c12b0Sopenharmony_ciwhich is "major version, minor version, patchlevel".  This shows up in
265e5c12b0Sopenharmony_cithe library name:
275e5c12b0Sopenharmony_ci
285e5c12b0Sopenharmony_ci	libudev.so.1.6.11
295e5c12b0Sopenharmony_ci
305e5c12b0Sopenharmony_ciSo in this example, the major version number is 1, the minor version
315e5c12b0Sopenharmony_ciis 6, and the patchlevel is 11.  The patchlevel is entirely optional,
325e5c12b0Sopenharmony_ciand many packages don't use it at all.  The minor number is also
335e5c12b0Sopenharmony_cimostly useless on Linux, but it's still there for historical reasons.
345e5c12b0Sopenharmony_ciThe patchlevel and minor version numbers were useful back for SunOS
355e5c12b0Sopenharmony_ci(and Linux a.out shared library), back when there weren't rpm and dpkg
365e5c12b0Sopenharmony_cias package managers.
375e5c12b0Sopenharmony_ci
385e5c12b0Sopenharmony_ciSo many modern Linux shared libraries will only use the major and
395e5c12b0Sopenharmony_ciminor version numbers, e.g:
405e5c12b0Sopenharmony_ci
415e5c12b0Sopenharmony_ci	libext2fs.so.2.4
425e5c12b0Sopenharmony_ci
435e5c12b0Sopenharmony_ciThe only thing you really need to worry about is the major version
445e5c12b0Sopenharmony_cinumber, really.  The minor version is *supposed* to change when new
455e5c12b0Sopenharmony_ciinterfaces has changed (but I and most other people don't do that any
465e5c12b0Sopenharmony_cimore).  But the big deal is that the major number *must* get bumped if
475e5c12b0Sopenharmony_cian existing interface has *changed*.
485e5c12b0Sopenharmony_ci
495e5c12b0Sopenharmony_ciSo let's talk about the major version number, and then we'll talk
505e5c12b0Sopenharmony_ciabout why the minor version number isn't really a big deal for Linux.
515e5c12b0Sopenharmony_ci
525e5c12b0Sopenharmony_ciSo if you change any of the library's function signatures --- and this
535e5c12b0Sopenharmony_ciincludes changing a type from a 32-bit integer to a 64-bit integer,
545e5c12b0Sopenharmony_cithat's an ABI breakage, and so you must bump the major version number
555e5c12b0Sopenharmony_ciso that a program that was linked against libfoo.so.4 doesn't try to
565e5c12b0Sopenharmony_ciuse libfoo.so.5.  That's really the key --- will a program linked
575e5c12b0Sopenharmony_ciagainst the previous version library break if it links against the
585e5c12b0Sopenharmony_cinewer version.  If it does, then you need to bump the version number.
595e5c12b0Sopenharmony_ci
605e5c12b0Sopenharmony_ciSo for structures, if you change any of the existing fields, or if the
615e5c12b0Sopenharmony_ciapplication program allocates the structure --- either by declaring it
625e5c12b0Sopenharmony_cion the stack, or via malloc() --- and you expand the structure,
635e5c12b0Sopenharmony_ciobviously that will cause problem, and so that's an ABI break.
645e5c12b0Sopenharmony_ci
655e5c12b0Sopenharmony_ciIf however, you arrange to have structures allocated by the library,
665e5c12b0Sopenharmony_ciand struct members are always added at the end, then an older program
675e5c12b0Sopenharmony_ciwon't have any problems.  You can guarantee this by simply only using
685e5c12b0Sopenharmony_cia pointer to the struct in your public header files, and defining the
695e5c12b0Sopenharmony_cistruct in a private header file that is not available to userspace
705e5c12b0Sopenharmony_ciprograms.
715e5c12b0Sopenharmony_ci
725e5c12b0Sopenharmony_ciSimilarly, adding new functions never breaks the ABI.  That's because
735e5c12b0Sopenharmony_ciolder program won't try to use the newer interfaces.  So if I need to
745e5c12b0Sopenharmony_cichange an interface to a function, what I'll generally do is to define
755e5c12b0Sopenharmony_cia new function, and then implement the older function in terms of the
765e5c12b0Sopenharmony_cinewer one.  For example:
775e5c12b0Sopenharmony_ci
785e5c12b0Sopenharmony_ciextern errcode_t ext2fs_open(const char *name, int flags, int superblock,
795e5c12b0Sopenharmony_ci			     unsigned int block_size, io_manager manager,
805e5c12b0Sopenharmony_ci			     ext2_filsys *ret_fs);
815e5c12b0Sopenharmony_ci
825e5c12b0Sopenharmony_ciextern errcode_t ext2fs_open2(const char *name, const char *io_options,
835e5c12b0Sopenharmony_ci			      int flags, int superblock,
845e5c12b0Sopenharmony_ci			      unsigned int block_size, io_manager manager,
855e5c12b0Sopenharmony_ci			      ext2_filsys *hret_fs);
865e5c12b0Sopenharmony_ci
875e5c12b0Sopenharmony_ciAs far as the minor version numbers are concerned, the dynamic linker
885e5c12b0Sopenharmony_cidoesn't use it.  In SunOS 4, if you have a DT_NEEDED for libfoo.so.4,
895e5c12b0Sopenharmony_ciand the dynamic linker finds in its search path:
905e5c12b0Sopenharmony_ci
915e5c12b0Sopenharmony_ci    libfoo.so.4.8
925e5c12b0Sopenharmony_ci    libfoo.so.4.9
935e5c12b0Sopenharmony_ci
945e5c12b0Sopenharmony_ciIt will preferentially use libfoo.so.4.9.
955e5c12b0Sopenharmony_ci
965e5c12b0Sopenharmony_ciThat's not how it works in Linux, though.  In Linux there will be a
975e5c12b0Sopenharmony_cisymlink that points libfoo.so.4 to libfoo.so.4.9, and the linker just
985e5c12b0Sopenharmony_cilooks for libfoo.so.4.  One could imagine a package manager which
995e5c12b0Sopenharmony_ciadjusts the symlink to point at the library with the highest version,
1005e5c12b0Sopenharmony_cibut given that libfoo.so.4.9 is supposed to contain a superset of
1015e5c12b0Sopenharmony_cilibfoo.so.4.8, there's no point.  So we just in practice handle all of
1025e5c12b0Sopenharmony_cithis in the package manager, or via an ELF symbol map.  Or, we just
1035e5c12b0Sopenharmony_ciassume that since vast majority of software comes from the
1045e5c12b0Sopenharmony_cidistribution, the distro package manager will just update libraries to
1055e5c12b0Sopenharmony_cithe newer version as a matter of course, and nothing special needs to
1065e5c12b0Sopenharmony_cibe done.
1075e5c12b0Sopenharmony_ci
1085e5c12b0Sopenharmony_ciSo in practice I don't bump the minor version number for e2fsprogs
1095e5c12b0Sopenharmony_cieach time I add new interfaces, because in practice it really doesn't
1105e5c12b0Sopenharmony_cimatter for Linux.  We have a much better system that gets used for
1115e5c12b0Sopenharmony_ciDebian.
1125e5c12b0Sopenharmony_ci
1135e5c12b0Sopenharmony_ciFor example in Debian there is a file that contains when each symbol
1145e5c12b0Sopenharmony_ciwas first introduced into a library, by its package version number.
1155e5c12b0Sopenharmony_ciSee:
1165e5c12b0Sopenharmony_ci
1175e5c12b0Sopenharmony_cihttps://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/tree/debian/libext2fs2.symbols
1185e5c12b0Sopenharmony_ci
1195e5c12b0Sopenharmony_ciThis file contains a version number for each symbol in libext2fs2, and
1205e5c12b0Sopenharmony_ciit tells us what version of libext2fs you need to guarantee that a
1215e5c12b0Sopenharmony_ciparticular symbol is present in the library.  Then when *other*
1225e5c12b0Sopenharmony_cipackages are built that depend on libext2fs2, the minimum version of
1235e5c12b0Sopenharmony_cilibext2fs can be calculated based on which symbols they use.
1245e5c12b0Sopenharmony_ci
1255e5c12b0Sopenharmony_ciSo for example the libf2fs-format4 package has a Debian dependency of:
1265e5c12b0Sopenharmony_ci
1275e5c12b0Sopenharmony_ciDepends: libblkid1 (>= 2.17.2), libc6 (>= 2.14), libf2fs5, libuuid1 (>= 2.16)
1285e5c12b0Sopenharmony_ci
1295e5c12b0Sopenharmony_ciThe minimum version numbers needed for libblkid1 and libuuid1 are
1305e5c12b0Sopenharmony_cidetermined by figuring out all of the symbols used by the
1315e5c12b0Sopenharmony_cilibf2fs-format4 package, and determining the minimum version number of
1325e5c12b0Sopenharmony_cilibblkid1 that supports all of those blkid functions.
1335e5c12b0Sopenharmony_ci
1345e5c12b0Sopenharmony_ciThis gets done automatically, so I didn't have to figure this out.
1355e5c12b0Sopenharmony_ciAll I have in the debian/control file is:
1365e5c12b0Sopenharmony_ci
1375e5c12b0Sopenharmony_ciDepends: ${misc:Depends}, ${shlibs:Depends}
1385e5c12b0Sopenharmony_ci
1395e5c12b0Sopenharmony_ciSorry this got so long, but hopefully you'll find this useful.  How
1405e5c12b0Sopenharmony_ciyou bend libtool to your will is something you'll have to figure out,
1415e5c12b0Sopenharmony_cibecause I don't use libtool in my packages.[1]
1425e5c12b0Sopenharmony_ci
1435e5c12b0Sopenharmony_ciCheers,
1445e5c12b0Sopenharmony_ci
1455e5c12b0Sopenharmony_ci					- Ted
1465e5c12b0Sopenharmony_ci
1475e5c12b0Sopenharmony_ci
1485e5c12b0Sopenharmony_ci[1] If you are interested in how I do things in e2fsprogs, take a look
1495e5c12b0Sopenharmony_ciat the Makefile.elf-lib, Makefile.solaris-lib, Makefile.darwin-lib,
1505e5c12b0Sopenharmony_cietc. here:
1515e5c12b0Sopenharmony_ci
1525e5c12b0Sopenharmony_cihttps://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/tree/lib
1535e5c12b0Sopenharmony_ci
1545e5c12b0Sopenharmony_ciThis these Makefile fragments are then pulled into the generated
1555e5c12b0Sopenharmony_cimakefile using autoconf's substitution rules, here:
1565e5c12b0Sopenharmony_ci
1575e5c12b0Sopenharmony_cihttps://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/tree/lib/ext2fs/Makefile.in
1585e5c12b0Sopenharmony_ci
1595e5c12b0Sopenharmony_ci(Search for "@MAKEFILE_ELF@" in the above Makefile.in).
1605e5c12b0Sopenharmony_ci
1615e5c12b0Sopenharmony_ciSo when someone runs "configure --enable-elf-shlibs", they get the ELF
1625e5c12b0Sopenharmony_cishared libraries built.  On BSD and MacOS systems they just have to
1635e5c12b0Sopenharmony_cirun "configure --enable-bsd-shlibs", and so on.
1645e5c12b0Sopenharmony_ci
1655e5c12b0Sopenharmony_ciPersonally, since most people don't bother to write truly portable
1665e5c12b0Sopenharmony_ciprograms, as their C code is full of Linux'isms, using libtool is just
1675e5c12b0Sopenharmony_cioverkill, because they probably can't build on any other OS *anyway*
1685e5c12b0Sopenharmony_ciso libtool's slow and complex abstraction layer is totally wasted.
1695e5c12b0Sopenharmony_ciMight as well not use autoconf, automake, and libtool at all.
1705e5c12b0Sopenharmony_ci
1715e5c12b0Sopenharmony_ciOn the other hand, if you really *do* worry about portability on other
1725e5c12b0Sopenharmony_ciOS's (e2fsprogs builds on MacOS, NetBSD, Hurd, Solaris, etc.) then
1735e5c12b0Sopenharmony_ciusing autoconf makes sense --- but I *still* don't think the
1745e5c12b0Sopenharmony_cicomplexity of libtool is worth it.
1755e5c12b0Sopenharmony_ci
1765e5c12b0Sopenharmony_ci= Add-on =
1775e5c12b0Sopenharmony_ciIf you are going to be making one less major update, this is the
1785e5c12b0Sopenharmony_ciperfect time to make sure that data structures are allocated by the
1795e5c12b0Sopenharmony_cilibrary, and are (ideally) opaque to the calling application (so they
1805e5c12b0Sopenharmony_cionly manipulate structure poitners).  That is, the structure
1815e5c12b0Sopenharmony_cidefinition is not exposed in the public header file, and you use
1825e5c12b0Sopenharmony_ciaccessor functions to set and get fields in the structure.
1835e5c12b0Sopenharmony_ci
1845e5c12b0Sopenharmony_ciIf you can't do that for all data structures, if you can do that with
1855e5c12b0Sopenharmony_ciyour primary data structure that's going to make your life much easier
1865e5c12b0Sopenharmony_ciin the long term.  For ext2fs, that's the file systme handle.  It's
1875e5c12b0Sopenharmony_cicreated by ext2fs_open(), and it's passed to all other library
1885e5c12b0Sopenharmony_cifunctions as the first argument.
1895e5c12b0Sopenharmony_ci
1905e5c12b0Sopenharmony_ciThe other thing you might want to consider doing is adding a magic
1915e5c12b0Sopenharmony_cinumber to the beginning of each structure.  That way you can tell if
1925e5c12b0Sopenharmony_cithe wrong structure gets passed to a library.  It's also helpful for
1935e5c12b0Sopenharmony_cidoing the equivalent of subclassing in C.
1945e5c12b0Sopenharmony_ci
1955e5c12b0Sopenharmony_ciThis is how we do it in libext2fs --- we use com_err to define the
1965e5c12b0Sopenharmony_cimagic numbers:
1975e5c12b0Sopenharmony_ci
1985e5c12b0Sopenharmony_ci	error_table ext2
1995e5c12b0Sopenharmony_ci
2005e5c12b0Sopenharmony_ciec	EXT2_ET_BASE,
2015e5c12b0Sopenharmony_ci	"EXT2FS Library version @E2FSPROGS_VERSION@"
2025e5c12b0Sopenharmony_ci
2035e5c12b0Sopenharmony_ciec	EXT2_ET_MAGIC_EXT2FS_FILSYS,
2045e5c12b0Sopenharmony_ci	"Wrong magic number for ext2_filsys structure"
2055e5c12b0Sopenharmony_ci
2065e5c12b0Sopenharmony_ciec	EXT2_ET_MAGIC_BADBLOCKS_LIST,
2075e5c12b0Sopenharmony_ci	"Wrong magic number for badblocks_list structure"
2085e5c12b0Sopenharmony_ci	...
2095e5c12b0Sopenharmony_ci
2105e5c12b0Sopenharmony_ciAnd then every single structure starts like so:
2115e5c12b0Sopenharmony_ci
2125e5c12b0Sopenharmony_cistruct struct_ext2_filsys {
2135e5c12b0Sopenharmony_ci	errcode_t			magic;
2145e5c12b0Sopenharmony_ci	...
2155e5c12b0Sopenharmony_ci
2165e5c12b0Sopenharmony_cistruct ext2_struct_inode_scan {
2175e5c12b0Sopenharmony_ci	errcode_t		magic;
2185e5c12b0Sopenharmony_ci	...
2195e5c12b0Sopenharmony_ci
2205e5c12b0Sopenharmony_ciAnd then before we use any pointer we do this:
2215e5c12b0Sopenharmony_ci
2225e5c12b0Sopenharmony_ci	if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
2235e5c12b0Sopenharmony_ci		return EXT2_ET_MAGIC_EXT2_FILE;
224