linux-f2fs-devel.lists.sourceforge.net archive mirror
 help / color / mirror / Atom feed
From: "Theodore Y. Ts'o" <tytso@mit.edu>
To: Jaegeuk Kim <jaegeuk@kernel.org>
Cc: linux-f2fs-devel@lists.sourceforge.net
Subject: Re: [PATCH 1/2] add cotnfigure option --with-root-libdir
Date: Tue, 28 Aug 2018 23:10:40 -0400	[thread overview]
Message-ID: <20180829031040.GE19128@thunk.org> (raw)
In-Reply-To: <20180828165944.GA62482@jaegeuk-macbookpro.roam.corp.google.com>

On Tue, Aug 28, 2018 at 09:59:44AM -0700, Jaegeuk Kim wrote:
> 
> https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
> 
> I understood that, if there is no interface change but some implementation
> changes, I need to bump revision. If new interface is added, for example, I
> need to bump current while revision=0 and age++.

So part of the problem here is that libtool is doing something really
strange because they are trying to use some abstract concept that is
OS-independent.  I don't use libtool because I find it horribly
complex and doesn't add enough value to be worth the complexity.

So I'll tell you how things work with respect to Linux's ELF version
numbering system.  Translating this to libtool's wierd "current,
revision, age" terminology is left as an exercise to the reader.  I've
looked at the libtool documentation, and it confuses me horribly.
Reading it, I suspect it's wrong, but I don't have the time to
experiment to confirm that the documentation is wrong and how it
diverges from the libtool implementation.

So let me explain things using the ELF shared library terminology,
which is "major version, minor version, patchlevel".  This shows up in
the library name:
    
	libudev.so.1.6.11

So in this example, the major version number is 1, the minor version
is 6, and the patchlevel is 11.  The patchlevel is entirely optional,
and many packages don't use it at all.  The minor number is also
mostly useless on Linux, but it's still there for historical reasons.
The patchlevel and minor version numbers were useful back for SunOS
(and Linux a.out shared library), back when there weren't rpm and dpkg
as package managers.

So many modern Linux shared libraries will only use the major and
minor version numbers, e.g:

	libext2fs.so.2.4

The only thing you really need to worry about is the major version
number, really.  The minor version is *supposed* to change when new
interfaces has changed (but I and most other people don't do that any
more).  But the big deal is that the major number *must* get bumped if
an existing interface has *changed*.

So let's talk about the major version number, and then we'll talk
about why the minor version number isn't really a big deal for Linux.

So if you change any of the library's function signatures --- and this
includes changing a type from a 32-bit integer to a 64-bit integer,
that's an ABI breakage, and so you must bump the major version number
so that a program that was linked against libfoo.so.4 doesn't try to
use libfoo.so.5.  That's really the key --- will a program linked
against the previous version library break if it links against the
newer version.  If it does, then you need to bump the version number.

So for structures, if you change any of the existing fields, or if the
application program allocates the structure --- either by declaring it
on the stack, or via malloc() --- and you expand the structure,
obviously that will cause problem, and so that's an ABI break.

If however, you arrange to have structures allocated by the library,
and struct members are always added at the end, then an older program
won't have any problems.  You can guarantee this by simply only using
a pointer to the struct in your public header files, and defining the
struct in a private header file that is not available to userspace
programs.

Similarly, adding new functions never breaks the ABI.  That's because
older program won't try to use the newer interfaces.  So if I need to
change an interface to a function, what I'll generally do is to define
a new function, and then implement the older function in terms of the
newer one.  For example:

extern errcode_t ext2fs_open(const char *name, int flags, int superblock,
			     unsigned int block_size, io_manager manager,
			     ext2_filsys *ret_fs);
			     
extern errcode_t ext2fs_open2(const char *name, const char *io_options,
			      int flags, int superblock,
			      unsigned int block_size, io_manager manager,
			      ext2_filsys *hret_fs);

As far as the minor version numbers are concerned, the dynamic linker
doesn't use it.  In SunOS 4, if you have a DT_NEEDED for libfoo.so.4,
and the dynamic linker finds in its search path:

    libfoo.so.4.8
    libfoo.so.4.9

It will preferentially use libfoo.so.4.9.

That's not how it works in Linux, though.  In Linux there will be a
symlink that points libfoo.so.4 to libfoo.so.4.9, and the linker just
looks for libfoo.so.4.  One could imagine a package manager which
adjusts the symlink to point at the library with the highest version,
but given that libfoo.so.4.9 is supposed to contain a superset of
libfoo.so.4.8, there's no point.  So we just in practice handle all of
this in the package manager, or via an ELF symbol map.  Or, we just
assume that since vast majority of software comes from the
distribution, the distro package manager will just update libraries to
the newer version as a matter of course, and nothing special needs to
be done.

So in practice I don't bump the minor version number for e2fsprogs
each time I add new interfaces, because in practice it really doesn't
matter for Linux.  We have a much better system that gets used for
Debian.

For example in Debian there is a file that contains when each symbol
was first introduced into a library, by its package version number.
See:

https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/tree/debian/libext2fs2.symbols

This file contains a version number for each symbol in libext2fs2, and
it tells us what version of libext2fs you need to guarantee that a
particular symbol is present in the library.  Then when *other*
packages are built that depend on libext2fs2, the minimum version of
libext2fs can be calculated based on which symbols they use.

So for example the libf2fs-format4 package has a Debian dependency of:

Depends: libblkid1 (>= 2.17.2), libc6 (>= 2.14), libf2fs5, libuuid1 (>= 2.16)

The minimum version numbers needed for libblkid1 and libuuid1 are
determined by figuring out all of the symbols used by the
libf2fs-format4 package, and determining the minimum version number of
libblkid1 that supports all of those blkid functions.

This gets done automatically, so I didn't have to figure this out.
All I have in the debian/control file is:

Depends: ${misc:Depends}, ${shlibs:Depends}

Sorry this got so long, but hopefully you'll find this useful.  How
you bend libtool to your will is something you'll have to figure out,
because I don't use libtool in my packages.[1]

Cheers,

					- Ted


[1] If you are interested in how I do things in e2fsprogs, take a look
at the Makefile.elf-lib, Makefile.solaris-lib, Makefile.darwin-lib,
etc. here:

https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/tree/lib

This these Makefile fragments are then pulled into the generated
makefile using autoconf's substitution rules, here:

https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/tree/lib/ext2fs/Makefile.in

(Search for "@MAKEFILE_ELF@" in the above Makefile.in).

So when someone runs "configure --enable-elf-shlibs", they get the ELF
shared libraries built.  On BSD and MacOS systems they just have to
run "configure --enable-bsd-shlibs", and so on.

Personally, since most people don't bother to write truly portable
programs, as their C code is full of Linux'isms, using libtool is just
overkill, because they probably can't build on any other OS *anyway*
so libtool's slow and complex abstraction layer is totally wasted.
Might as well not use autoconf, automake, and libtool at all.

On the other hand, if you really *do* worry about portability on other
OS's (e2fsprogs builds on MacOS, NetBSD, Hurd, Solaris, etc.) then
using autoconf makes sense --- but I *still* don't think the
complexity of libtool is worth it.


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot

  reply	other threads:[~2018-08-29  3:10 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-20  3:04 [PATCH 1/2] add configure option --with-root-libdir Theodore Ts'o
2018-08-20  3:04 ` [PATCH 2/2] Ask git to ignore the generated sg_write_buffer executable Theodore Ts'o
2018-08-20  7:21   ` Chao Yu
2018-08-27 15:51 ` [PATCH 1/2] add configure option --with-root-libdir Theodore Y. Ts'o
2018-08-27 16:57   ` Jaegeuk Kim
2018-08-27 23:56     ` Theodore Y. Ts'o
2018-08-28  7:12       ` Jaegeuk Kim
2018-08-28 14:25         ` Theodore Y. Ts'o
2018-08-28 16:59           ` Jaegeuk Kim
2018-08-29  3:10             ` Theodore Y. Ts'o [this message]
2018-08-29 21:04               ` [PATCH 1/2] add cotnfigure " Jaegeuk Kim
2018-08-29 23:51                 ` Theodore Y. Ts'o
2018-08-28  3:43 ` [PATCH 1/2] add configure " Chao Yu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180829031040.GE19128@thunk.org \
    --to=tytso@mit.edu \
    --cc=jaegeuk@kernel.org \
    --cc=linux-f2fs-devel@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).