1 ------------------- 2 Written by Ted T'so 3 ------------------- 4 5 > https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html 6 > 7 > I understood that, if there is no interface change but some implementation 8 > changes, I need to bump revision. If new interface is added, for example, I 9 > need to bump current while revision=0 and age++. 10 11 So part of the problem here is that libtool is doing something really 12 strange because they are trying to use some abstract concept that is 13 OS-independent. I don't use libtool because I find it horribly 14 complex and doesn't add enough value to be worth the complexity. 15 16 So I'll tell you how things work with respect to Linux's ELF version 17 numbering system. Translating this to libtool's wierd "current, 18 revision, age" terminology is left as an exercise to the reader. I've 19 looked at the libtool documentation, and it confuses me horribly. 20 Reading it, I suspect it's wrong, but I don't have the time to 21 experiment to confirm that the documentation is wrong and how it 22 diverges from the libtool implementation. 23 24 So let me explain things using the ELF shared library terminology, 25 which is "major version, minor version, patchlevel". This shows up in 26 the library name: 27 28 libudev.so.1.6.11 29 30 So in this example, the major version number is 1, the minor version 31 is 6, and the patchlevel is 11. The patchlevel is entirely optional, 32 and many packages don't use it at all. The minor number is also 33 mostly useless on Linux, but it's still there for historical reasons. 34 The patchlevel and minor version numbers were useful back for SunOS 35 (and Linux a.out shared library), back when there weren't rpm and dpkg 36 as package managers. 37 38 So many modern Linux shared libraries will only use the major and 39 minor version numbers, e.g: 40 41 libext2fs.so.2.4 42 43 The only thing you really need to worry about is the major version 44 number, really. The minor version is *supposed* to change when new 45 interfaces has changed (but I and most other people don't do that any 46 more). But the big deal is that the major number *must* get bumped if 47 an existing interface has *changed*. 48 49 So let's talk about the major version number, and then we'll talk 50 about why the minor version number isn't really a big deal for Linux. 51 52 So if you change any of the library's function signatures --- and this 53 includes changing a type from a 32-bit integer to a 64-bit integer, 54 that's an ABI breakage, and so you must bump the major version number 55 so that a program that was linked against libfoo.so.4 doesn't try to 56 use libfoo.so.5. That's really the key --- will a program linked 57 against the previous version library break if it links against the 58 newer version. If it does, then you need to bump the version number. 59 60 So for structures, if you change any of the existing fields, or if the 61 application program allocates the structure --- either by declaring it 62 on the stack, or via malloc() --- and you expand the structure, 63 obviously that will cause problem, and so that's an ABI break. 64 65 If however, you arrange to have structures allocated by the library, 66 and struct members are always added at the end, then an older program 67 won't have any problems. You can guarantee this by simply only using 68 a pointer to the struct in your public header files, and defining the 69 struct in a private header file that is not available to userspace 70 programs. 71 72 Similarly, adding new functions never breaks the ABI. That's because 73 older program won't try to use the newer interfaces. So if I need to 74 change an interface to a function, what I'll generally do is to define 75 a new function, and then implement the older function in terms of the 76 newer one. For example: 77 78 extern errcode_t ext2fs_open(const char *name, int flags, int superblock, 79 unsigned int block_size, io_manager manager, 80 ext2_filsys *ret_fs); 81 82 extern errcode_t ext2fs_open2(const char *name, const char *io_options, 83 int flags, int superblock, 84 unsigned int block_size, io_manager manager, 85 ext2_filsys *hret_fs); 86 87 As far as the minor version numbers are concerned, the dynamic linker 88 doesn't use it. In SunOS 4, if you have a DT_NEEDED for libfoo.so.4, 89 and the dynamic linker finds in its search path: 90 91 libfoo.so.4.8 92 libfoo.so.4.9 93 94 It will preferentially use libfoo.so.4.9. 95 96 That's not how it works in Linux, though. In Linux there will be a 97 symlink that points libfoo.so.4 to libfoo.so.4.9, and the linker just 98 looks for libfoo.so.4. One could imagine a package manager which 99 adjusts the symlink to point at the library with the highest version, 100 but given that libfoo.so.4.9 is supposed to contain a superset of 101 libfoo.so.4.8, there's no point. So we just in practice handle all of 102 this in the package manager, or via an ELF symbol map. Or, we just 103 assume that since vast majority of software comes from the 104 distribution, the distro package manager will just update libraries to 105 the newer version as a matter of course, and nothing special needs to 106 be done. 107 108 So in practice I don't bump the minor version number for e2fsprogs 109 each time I add new interfaces, because in practice it really doesn't 110 matter for Linux. We have a much better system that gets used for 111 Debian. 112 113 For example in Debian there is a file that contains when each symbol 114 was first introduced into a library, by its package version number. 115 See: 116 117 https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/tree/debian/libext2fs2.symbols 118 119 This file contains a version number for each symbol in libext2fs2, and 120 it tells us what version of libext2fs you need to guarantee that a 121 particular symbol is present in the library. Then when *other* 122 packages are built that depend on libext2fs2, the minimum version of 123 libext2fs can be calculated based on which symbols they use. 124 125 So for example the libf2fs-format4 package has a Debian dependency of: 126 127 Depends: libblkid1 (>= 2.17.2), libc6 (>= 2.14), libf2fs5, libuuid1 (>= 2.16) 128 129 The minimum version numbers needed for libblkid1 and libuuid1 are 130 determined by figuring out all of the symbols used by the 131 libf2fs-format4 package, and determining the minimum version number of 132 libblkid1 that supports all of those blkid functions. 133 134 This gets done automatically, so I didn't have to figure this out. 135 All I have in the debian/control file is: 136 137 Depends: ${misc:Depends}, ${shlibs:Depends} 138 139 Sorry this got so long, but hopefully you'll find this useful. How 140 you bend libtool to your will is something you'll have to figure out, 141 because I don't use libtool in my packages.[1] 142 143 Cheers, 144 145 - Ted 146 147 148 [1] If you are interested in how I do things in e2fsprogs, take a look 149 at the Makefile.elf-lib, Makefile.solaris-lib, Makefile.darwin-lib, 150 etc. here: 151 152 https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/tree/lib 153 154 This these Makefile fragments are then pulled into the generated 155 makefile using autoconf's substitution rules, here: 156 157 https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/tree/lib/ext2fs/Makefile.in 158 159 (Search for "@MAKEFILE_ELF@" in the above Makefile.in). 160 161 So when someone runs "configure --enable-elf-shlibs", they get the ELF 162 shared libraries built. On BSD and MacOS systems they just have to 163 run "configure --enable-bsd-shlibs", and so on. 164 165 Personally, since most people don't bother to write truly portable 166 programs, as their C code is full of Linux'isms, using libtool is just 167 overkill, because they probably can't build on any other OS *anyway* 168 so libtool's slow and complex abstraction layer is totally wasted. 169 Might as well not use autoconf, automake, and libtool at all. 170 171 On the other hand, if you really *do* worry about portability on other 172 OS's (e2fsprogs builds on MacOS, NetBSD, Hurd, Solaris, etc.) then 173 using autoconf makes sense --- but I *still* don't think the 174 complexity of libtool is worth it. 175 176 = Add-on = 177 If you are going to be making one less major update, this is the 178 perfect time to make sure that data structures are allocated by the 179 library, and are (ideally) opaque to the calling application (so they 180 only manipulate structure poitners). That is, the structure 181 definition is not exposed in the public header file, and you use 182 accessor functions to set and get fields in the structure. 183 184 If you can't do that for all data structures, if you can do that with 185 your primary data structure that's going to make your life much easier 186 in the long term. For ext2fs, that's the file systme handle. It's 187 created by ext2fs_open(), and it's passed to all other library 188 functions as the first argument. 189 190 The other thing you might want to consider doing is adding a magic 191 number to the beginning of each structure. That way you can tell if 192 the wrong structure gets passed to a library. It's also helpful for 193 doing the equivalent of subclassing in C. 194 195 This is how we do it in libext2fs --- we use com_err to define the 196 magic numbers: 197 198 error_table ext2 199 200 ec EXT2_ET_BASE, 201 "EXT2FS Library version @E2FSPROGS_VERSION@" 202 203 ec EXT2_ET_MAGIC_EXT2FS_FILSYS, 204 "Wrong magic number for ext2_filsys structure" 205 206 ec EXT2_ET_MAGIC_BADBLOCKS_LIST, 207 "Wrong magic number for badblocks_list structure" 208 ... 209 210 And then every single structure starts like so: 211 212 struct struct_ext2_filsys { 213 errcode_t magic; 214 ... 215 216 struct ext2_struct_inode_scan { 217 errcode_t magic; 218 ... 219 220 And then before we use any pointer we do this: 221 222 if (file->magic != EXT2_ET_MAGIC_EXT2_FILE) 223 return EXT2_ET_MAGIC_EXT2_FILE; 224