This session was presented by Stefan Potyra and Steve Langasek on 18th January 2008.

20:06   sistpoty        so a big welcome to everyone for joining the motu school session about library packaging
20:06   sistpoty        the session will be split in two parts:
20:07   sistpoty        in the first part, we'll dive deeply into the background of shared objects, and how to find out information about these
20:07   sistpoty        and in the second part, we'll go through creating a library package by example
20:07   sistpoty        so let's start with part 1
20:07   sistpoty        First off, shared objects are useful for two different purposes
20:08   sistpoty        1) as a plugin mechanism in conjunction with dlopen
20:08   sistpoty        2) for dynamic libraries, to share code between different projects
20:08   sistpoty        as this is about library packaging, we'll be only looking at 2) in this session
20:09   sistpoty        First off, (ELF) shared objects are a collection of symbols in different sections together with some meta-information
20:09   sistpoty        a symbol denotes a named entity in C (e.g. a function or a variable)
20:09   sistpoty        the section will give us some detail about the symbol
20:10   sistpoty        btw.: if you have questions, just ask ;)
20:10   sistpoty        let's take a look at an example:
20:10   sistpoty        so please everyone download the file
20:11   sistpoty        everyone got it?
20:11   warp10  yep!
20:11   mok0    +
20:11   sistpoty        great, so let's compile the file:
20:11   sistpoty        gcc -c example.c -o example.o
20:12   sistpoty        so far, the .o is just a normal object, not a shared object yet... however we can do some stuff with it already
20:12   sistpoty        now run
20:12   sistpoty        nm example.o
20:12   sistpoty        the output are the different symbols defined in example.c
20:14   mok0    what are the letters U, T, t...
20:14   sistpoty        for example in line 3, the variable "static_global" is results as symbol "0000000000000000 d static_global"
20:14   sistpoty        mok0: will talk about that in a second ;)
20:14   sistpoty        when you compare the output of nm, together with the variables of example.c, does anyone see anything odd?
20:15   sistpoty        I'll give you a hint: look at the beginning of the function local_function
20:16   sistpoty        now, anyone?
20:16   warp10  why local_var isn't listed?
20:16   sistpoty        warp10: excellent
20:16   mok0    it's allocated on the call stack
20:17   geser   why does static_local_var has a number in the nm output (here: static_local_var.2268)?
20:17   sistpoty        excactly... some symbols in C (like local_var) don't need to be stored anywhere, because these are located in the stack
20:18   sistpoty        ok, and some variables (like static_local_var) won't result in the same symbols as they are named. This is because the variable is not visible anywhere but in the function, and you can name a variable like this anywhere else
20:18   slangasek       geser: that's a very good question whose answer I don't remember :)
20:18   sistpoty        and you cannot have two symbols with the same name of course
20:18   mok0    geser: could that number be the offset?
20:19   sistpoty        any more questions or shall we go to the funny letters?
20:19   mok0    ^^
20:19   slangasek       mok0: it's not the offset
20:19   warp10  What's the order with which symbols are listed by nm?
20:19   sistpoty        warp10: good question: slangasek?
20:20   slangasek       plain alphabetical
20:20   siretart        slangasek: in order to avoid name clashes between different static local variables with the same name in different functions?
20:20   sistpoty        mok0: I guess it's just a counted number gcc will assign, but I may err on this side
20:20   mok0    sistpoty: my number is != gesers
20:20   geser   mok0: it could be the line number after including all headers. after changeing the line with the previous one the number is now 2267
20:21   slangasek       siretart: probably, yes
20:21   sistpoty        mok0: he, ah
20:21   mok0    static_local_var.1781
20:21   slangasek       siretart, geser: suffice to say, it goes away once you've linked the object into a shared library, so it ends up not being very relevant
20:22   sistpoty        ok, then now let's take a look at the letters.
20:22   sistpoty        First off, some are lower case and some are upper case.
20:22   slangasek       geser: it isn't the line number; if I run the source through gcc -E, I get line 757
20:22   geser   ok
20:22   sistpoty        The lower case letters denominate local symbols. Noone except this very object file can see these kind of symbols
20:23   mok0    lower case == local, Upper case == global
20:23   sistpoty        whereas the upper case letters mean that the symbol is global, and other object files are global... exactly.
20:23   sistpoty        the letter denote the type of the symbol:
20:23   sistpoty        t -> text section (may be mapped readonly), executable
20:23   sistpoty        d -> initialized data (statics, initialized globals)
20:23   sistpoty        (as in variables)
20:24   sistpoty        c -> uninitialized data (uninitialized global variables)
20:24   sistpoty        r -> read only data (const variables), not necessarily read only though.
20:24   slangasek       (btw, if you later don't remember what these letters map to, they're listed in man nm)
20:24   sistpoty        and then there's an interesting one: u
20:24   sistpoty        this means that the symbol is not defined in the object, but somewhere else
20:25   sistpoty        (undefined)
20:25   slangasek       to clarify, that means the object *refers* to the symbol but does not define it
20:25   sistpoty        so "stderr" is listed there, as it comes somewhere from the c library, as well as fprintf
20:26   sistpoty        ok, now let's make a shared object from this file:
20:26   sistpoty        gcc -Wl,-z,defs -Wl,-soname, -fPIC -shared example.c -o
20:27   sistpoty        everyone got it?
20:27   warp10  y
20:27   mok0    +
20:27   sistpoty        ok, now let's look again at it with nm
20:28   warp10  wow...
20:29   sistpoty        (you can ignore anything with an underscore, that's internal stuff)
20:29   bddebian        nm is like objdump?
20:29   slangasek       yes
20:29   bddebian        ok
20:29   slangasek       I might suggest at this point also running 'nm -D', for comparison
20:29   sistpoty        erm... sorry, we need to do another thing I forgot... let's first strip off the debugging symbols
20:30   sistpoty        strip
20:30   slangasek       ... or that :)
20:30   geser   nm: no symbols
20:30   mok0    hehe
20:31   mok0    that's easy :-)
20:31   sistpoty        ok, to look at the dynamic symbols, you'll now want nm -D as slangasek suggested
20:32   slangasek       right - since we strip binaries by default, 'nm' in the wild is going to give you empty output
20:32   geser   the local symbols aren't listed anymore?
20:32   sistpoty        what you'll see is that there are now (apart from some internals) only global symbols left. i.e. everything not defined as "static"
20:32   sistpoty        exactly
20:33   sistpoty        (side note: the static modifier in c means that the resulting symbol will be a local symbol)
20:34   sistpoty        any questions so far? then let's try some other tools on the shared object
20:34   mok0    sistpoty: well, global to the functions in that file
20:34   sistpoty        mok0: yes, a local global *g*
20:34   bddebian        hrh
20:34   slangasek       geser: since they're local, they're by definition not accessible to other things linking to this code; so aside from debugging symbols, which we've used 'strip' to wipe out, there's no reason to take up space by keeping around names for these variables
20:35   sistpoty        ok, now let's take a look at the meta-information:
20:35   sistpoty        objdump -x
20:36   sistpoty        this will give lots of info. The most interesting stuff can be found with objdump -p as well
20:37   bddebian        Who uses anything more than |grep SONAME? ;-)
* slangasek raises his hand
20:37   sistpoty        one thing that's in there is the SONAME, we'll take a look at it later
20:37   sistpoty        the other thing in there is the NEEDED entry (or entries)
20:38   sistpoty        the SONAME denotes the ABI-Verison of the shared object...
20:38   sistpoty        everything with the same SONAME can be considered to be compatible
20:39   geser   if upstream doesn't make a mistake
20:39   bddebian        geser: Never happens ;)
20:39   slangasek       everything with the same SONAME *will be* considered compatible by, so it darn well better *be* compatible :)
20:39   sistpoty        geser: we'll just see what happens then ;)
20:39   sistpoty        the NEEDED entries denote what libraries this shared object needs. These refer to the SONAME of other libraries
20:40   sistpoty        I guess everyone knows ldd, let's try that one
20:40   sistpoty        ldd
20:41   sistpoty        ldd will resolve any shared libraries a binary or a shared object needs
20:42   geser   is provided by the kernel?
20:42   sistpoty        so, what's the difference between the NEEDED entries and the output of ldd apart from the pathname?
20:42   slangasek       geser: yes, linux-vdso is a bit of Magic
20:43   warp10  ldd output shows three entries, not just one
20:43   geser   ldd resolves them recursively
* bddebian thinks geser is too smart for this class :)
20:43   sistpoty        exactly what geser said :)
20:43   geser   bddebian: :P
20:43   sistpoty        so you should keep these in mind when dealing with shared objects, as you might want to look at the *direct* dependencies as well
20:44   slangasek       yes; for a real world-example, have a look at ldd /usr/lib/, vs. objdump -p /usr/lib/ | grep NEEDED
20:45   slangasek       so we've looked at the output of nm -D on this object, but nm -D has one weakness as a tool which is not at all obvious if you don't already know what's missing
20:46   slangasek       have a look at the output of nm -D again
20:46   slangasek       now, compare it to the output of readelf -s
20:46   slangasek       who can spot the difference in the names?
20:47   bddebian        The stuff from @@glibc?
20:47   geser   you mean the versioned symbols?
20:47   slangasek       yep - nm -D doesn't show symbol versions
20:47   mok0    cool
20:48   slangasek       so if you want to get at those, you'll want to use objdump -T or readelf -s
20:48   geser   what does the "(2)" in "6: 0000000000000000   144 FUNC    GLOBAL DEFAULT  UND fprintf@GLIBC_2.2.5 (2)" mean?
20:48   slangasek       symbol versions are sometimes important, so you'll want to keep these tools in mind -- sometimes, an app/lib will not know the symbol version it's supposed to use, and that indicates a bug!
20:49   slangasek       geser: I'm not sure, sorry
20:50   slangasek       I'd probably have to look at the readelf source to figure that out, the fields aren't all well-explained in the documentation
20:50   mok0    we can write a dependency resolver from these tools
20:50   slangasek       mok0: indeed, dpkg-shlibdeps uses these tools
20:51   sistpoty        ok, any more questions so far?
20:51   sistpoty        When writing a program, that uses a library, we want to make sure that the API of that library is stable.
20:52   sistpoty        If we want to distribute this program, we also want a stable ABI.
20:52   sistpoty        stable API means that my program compiles against the library and a newer version of it.
20:52   sistpoty        stable ABI means that the symbols stay the same
20:53   mok0    what if there are new symbols?
20:53   sistpoty        mok0: of course... I just wanted to correct myself
20:53   sistpoty        stable ABI means that there won't get any symbols removed, and their meaning is still the same
20:55   mok0    If you write code that corrects a bug, but the interface remains the same?
20:55   sistpoty        mok0: then the ABI and API is stable
20:56   sistpoty        (most likely)
20:56   mok0    ... but I would still want that programs exclusively use the fixed version
20:56   sistpoty        but let's first have some fun... as some newby upstream started to produce a library...
20:56   geser   mok0: if I'm correct you can change the implementation as long as function name, arguments and return type stay the same
20:57   sistpoty        mok0: you can do this (as upstream) only, if the library have some version string or date encoded
20:57   mok0    ok
20:57   sistpoty        mok0: or by advetising it on your homepage *g*
20:57   mok0    you can bump the minor version number
20:58   sistpoty        for the library: yes (I'll come to this part yet)
20:58   chiptoxic       how do you tell if a library has a stable API or ABI is it just by watching the version numbers of that library?
20:58   sistpoty        chiptoxic: I'd like to postpone this question, as I first want to show you an example
20:59   chiptoxic       ok
20:59   sistpoty        so please everyone get <>
20:59   sistpoty        if you've got it, extract it and compile it with
20:59   sistpoty        make
21:00   sistpoty        then install the result (as root) with
21:00   sistpoty        make install
21:00   sistpoty        (no worries, it will only copy files to the /usr/local/ namespace, and make uninstall removes it again)
21:01   sistpoty        everyone got so far? (then me types the commands as well)
21:02   mok0    make PREFIX=. install
21:02   mok0    does it locally
21:03   sistpoty        then you might have trouble upgrading the library
21:04   sistpoty        (or building an application against it, which we'll do as soon as everyone is finished)
* warp10 is done
21:04   sistpoty        ok, next step: of course we want that uses the library, so get <>
21:05   sistpoty        extract that somewhere else and also build the binary with "make"
21:06   sistpoty        if you've done that, you should have a cool binary hello_prog, which will print hello. you can even tell it how often it should print hello with the first argument
21:06   sistpoty        ./hello_prog 10
21:07   sistpoty        everyone got so far yet?
21:07   mok0    error while loading shared libraries: cannot open shared object file: No such file or directory
21:07   frigaut same here
21:07   geser   mok0: sudo ldconfig
21:08   mok0    geser: just doing what the teachers tell me .-)
21:07   warp10  and here too :)
21:07   slangasek       heh, did any of the people having this problem install to /usr/local?
21:08   slangasek       or did you all install to a different prefix?
21:08   james_w slangasek: /usr/local for me
21:08   slangasek       ah, ok
21:08   sistpoty        hehe
21:08   frigaut works now after ldconfig
21:08   sistpoty        of course I forgot to mention ldconfig
21:08   chiptoxic       mine works and i just did what you said and ran ldconfig
21:08   sistpoty        (still got it installed from testing *g*)
21:09   mok0    Yay, it says hello to me 10 times
21:09   kdub    you have to have /usr/local in your /etc/ of course
21:09   geser   sistpoty: "eventually run ldconfig now."
21:09   slangasek       kdub: in /etc/ actually... :)
21:09   sistpoty        geser: hehe, what a nice upstream *g*
21:10   geser   yep
21:10   sistpoty        now if it prints hello for everyone, let's remove the *library* again with
21:10   sistpoty        make uninstall (run as root)
21:11   sistpoty        now try again to run the hello_prog.
21:12   sistpoty        any results yet?
21:12   geser   ./hello_prog: error while loading shared libraries: cannot open shared object file: No such file or directory
21:12   mok0    boom
21:13   sistpoty        great, so (I guess what you expected) it won't work w.o. the library
21:13   sistpoty        now upstream has released a new version of the library... I guess you all want hot new stuff?
21:13   sistpoty        then get it at
21:13   sistpoty        we'll be compiling it again:
21:13   sistpoty        make
21:14   sistpoty        and install it again (run as root)
21:14   sistpoty        make install
21:14   mok0    If you install the library again, it works once more :-)
21:14   sistpoty        hehe
21:14   warp10  I don't think so :)
21:15   geser   ./hello_prog: symbol lookup error: ./hello_prog: undefined symbol: print_hello
21:15   sistpoty        (oh, if you haven't removed installed the new library, you could also try ldd ./hello_prog)
21:16   sistpoty        so what happened?
21:16   sistpoty        now let's try to make use of the knowledge we gathered so far
21:16   mok0    the application attempts to use the new library
21:17   sistpoty        mok0: exactly
21:17   sistpoty        let's take a look at the symbols of both shared objects (old library vs. new library)
21:17   mok0    => ABI has changed
21:17   sistpoty        excellent!
21:18   sistpoty        in the old library, we had the function: T print_hello
21:18   sistpoty        which upstream obviously renamed to just: T hello
21:19   sistpoty        when you start the program, one of the first steps is that undefined symbols will get resolved
* bddebian curses upstream
21:19   sistpoty        hehe
21:20   slangasek       yeah, I would think twice about packaging any libraries from this upstream ;)
21:20   sistpoty        which is done recursively for each shared object that is used
* sistpoty removes copyright notices *g*
21:20   mok0    This is why it is wrong to use the program version number for library versions
21:20   bddebian        heh
21:20   mok0    which a lot of upstream programmers don't understand
21:21   sistpoty        when the symbol lookup can't resolve one symbol.. well you just saw what happens.
21:21   sistpoty        ok, what we've seen now is an incompatibility on symbol level.
21:22   sistpoty        I hope with the tools you've learned so far, you can easily track those down
21:22   sistpoty        -> any removed symbol in a shared library is a problem, *if* the SONAME stays the same
21:23   mok0    so let's change it
21:24   sistpoty        mok0: feel free to change it, I guess you can figure this in the Makefile
21:24   mok0    I set major to 2
21:25   albert23        Wouldn't this be an API change, since print_hello is not defined anymore in hello.h?
21:25   albert23        I wouldn't expect this to compile anymore?
21:25   sistpoty        albert23: exactly: this is an API change as well
21:26   sistpoty        ok, but let's get back to the ABI...
21:27   sistpoty        symbols however cannot represent the signature of functions (i.e. number of parameters, type of parameters)
21:27   sistpoty        this is part of the ABI as well
21:27   sistpoty        if we want to look if this changed, we'll need to dig a little bit deeper
21:27   mok0    Now the program works again, because it finds the first version of the library
21:27   mok0    (I changed MAJOR to 2)
21:28   sistpoty        mok0: hehe, so you didn't unstall the old library?
21:28   chiptoxic       im not a programmer but is there a way you could put an alias in the code say print_hello is really hello so you dont break the api? or would that just be messy
21:28   mok0    sistpoty: I still have 1.0.1 but I removed 1.0.2
21:28   mok0    The new one is 2.0.1
21:29   sistpoty        chiptoxic: you could for example abuse the preprocessor: "define print_hello hello"
21:29   mok0    My experiment shows you can have several versions of the library present
21:29   sistpoty        er... #define print_hello hello
21:29   chiptoxic       ah cool, thanks
21:29   sistpoty        ok, back to the topic...
21:30   sistpoty        you can look at the debug information with gdb, so let's run
21:30   sistpoty        gdb
21:30   slangasek       mok0: exactly, and this is a key reason why we always use the full soname for the names of our library packages
21:30   geser   mok0: and now try the same on windows :)
21:30   sistpoty        inside gdb, you can look at the signatures of functions with
21:30   sistpoty        info functions
21:31   mok0    slangasek: you mean the major soname ?
21:31   slangasek       mok0: the "soname" is the value returned by objdump -p $lib | grep SONAME
21:31   mok0    slangasek: ok
21:31   slangasek       and set (hopefully) using the -Wl,-soname option at build time
21:32   sistpoty        mok0: the Makefile just puts $(MAJOR) and a name in the soname, but the real soname is in SONAME
21:32   slangasek       lintian knows the standard way to map sonames to package names, and warns you if your package is named differently.  but of course, we have to take care that upstream is handling their ABI right in the first place!
21:32   sistpoty        inside gdb, you can also display the types of variables with
21:32   sistpoty        info variables
=== \sh is now known as \sh_away
21:33   sistpoty        (which is uninteresting for though, since it doesn't define a global variable by itself)
21:33   sistpoty        everyone looked at the output of "info functions"?
21:34   mok0    just one: hello(void)
21:34   sistpoty        you should see like "void hello(void);" or "void print_hello(void);" there (depending which version you chose)
21:34   sistpoty        yes, so upstream is lazy as well *g*
* bddebian files upstream bug
21:35   sistpoty        now let's strip the shared object (which wasn't done during the build process):
21:35   sistpoty        strip
21:35   sistpoty        (outside gdb again)
21:36   sistpoty        and then call gdb again and look at the functions again
21:36   mok0    :-(
21:36   sistpoty        as you can see, these are all gone.
21:36   geser   mok0: install the -dbgsym package of it :)
21:37   mok0    heh
21:37   sistpoty        that's because these were part of the debug symbols, which have been stripped away
21:37   sistpoty        ok, so if we want to find out about the ABI-part of the signatures, it's a little bit tougher, but still doable
21:39   sistpoty        if a signature is changed (number of arguments and type of a function), it can lead to different results. Most probably it will segfault, since the library and the application no longer agree on what data they exchange)
21:39   sistpoty        an exception to this rule is C++
21:40   sistpoty        in C++ the signature is encoded in the name of a symbol
21:40   sistpoty        so if you change an argument, add an argument or remove one, you get a different symbol name
21:41   sistpoty        (side note: you can use nm -C to demangle these names back to a human readable signature)
21:41   slangasek       or c++filt
21:41   sistpoty        any questions so far?
21:42   sistpoty        chiptoxic: did that answer your question from some time ago?
21:42   slangasek       other side note, checking for ABI changes of this kind by hand is hard and tedious; there is a tool in universe that tries to automate this checking, called icheck
21:42   chiptoxic       yea, thanks
21:42   mok0    slangasek: icheck, what package?
21:43   sistpoty        slangasek: ah, nice :)
21:43   sistpoty        mok0: icheck
21:43   slangasek       if you're maintaining a library and want to be careful because your upstream isn't, icheck will let you generate a "manifest" from the old and new -dev packages, and compare them to see if the signatures have changed
* chiptoxic cant believe how much im learning :)
21:43   james_w slangasek: how does that compare to check-symbols from the ubuntu-dev-tools package?
* mok0 install icheck
21:43   slangasek       james_w: icheck examines headers, not symbols
21:44   slangasek       james_w: so it's specifically for the case where you're trying to detect the kinds of ABI changes that /don't/ show up in the symbol table
* bddebian can't keep up being at work :'-(
21:45   slangasek       (doh, check-symbols uses nm -D?  Baaad, what did we learn was the weakness of nm -D? :-)
21:45   sistpoty        slangasek: since you mentioned ABI changes not showing up in the symbol table, want to say a few words to these?
21:46   slangasek       probably, let me see where I put those words
21:47   slangasek       right - does everyone here understand why changing the arguments or return type of a function is an ABI change?
21:47   mok0    yes
21:47   slangasek       (if everyone knows, there's no sense in me spending time explaining it - but if you don't know, please speak up :)
21:48   warp10  y
21:48   mok0    Well renaming a global variable would show up
21:49   slangasek       two people know who care, everyone else is asleep or doesn't want to talk to me ;)
21:49   slangasek       sistpoty: back to you
21:49   slangasek       :)
21:49   mok0    I just tried icheck on the 2 library versions,
21:50   mok0    but I couldn't get it to work
21:50   sistpoty        ok
21:50   mok0    ... "Failed to parse
21:50   sistpoty        mok0: haven't used it myself yet
21:51   mok0    sistpoty: :-)
21:51   sistpoty        what we should have learned so far is that if the ABI breaks, you'll need to bump the SONAME
21:51   slangasek       mok0: you point it at the headers, not at the library
21:51   mok0    Ah!
21:51   sistpoty        however there is yet another case, we didn't consider
21:51   slangasek       that's the whole point - the library doesn't have the info you need about the function sigs :)
21:52   sistpoty        upstream might put additional functionality in the library
21:52   sistpoty        and keep the ABI downwards compatible
21:53   sistpoty        in that case, the SONAME would (and should) stay the same, because no program ceases to work with the newer library
21:53   sistpoty        however this has one caveat: people who use this library might make use of the new features
21:53   mok0    ... but new programs that use the new functionality?
21:54   sistpoty        right, so these programs wouldn't work with the old library but only with the new one (even though the SONAME is the same)
21:54   sistpoty        for this, there the SONAME is not sufficient alone.
21:55   sistpoty        slangasek: told me that historically the minor version was incremented for this
21:55   sistpoty        -:
* mok0 also read that
21:55   sistpoty        but that won't work if you copy binaries from one system to another (as you don't know about the libraries there)
21:56   sistpoty        ok, this pretty much was part 1 -- shared objects
21:56   sistpoty        any questions so far?
21:57   mok0    Well, what is the answer to the last problem?
21:57   sistpoty        mok0: we'll see that in part 2 :)
21:57   mok0    Arrghh
21:57   warp10  :)
21:57   mok0    It stops at the most exiting part
21:58   mok0    typical of these mini-series :-)

20:06   sistpoty        so who's around for part 2 of the library packaging session?
20:06   albert23        hello sistpoty
20:06   sistpoty        hi albert23
20:07   sistpoty        first off, there is an excellent guide about debian library packaging. We'll use this one as a reference for this session:
20:07   sistpoty
20:09   nixternal       thanks sistpoty for the wakeup call :)
20:09   sistpoty        hi nixternal :)
20:09   nixternal       well howdy
20:09   sistpoty        ok, in part 1, we hopefully learned all the basic stuff about shared objects.
20:10   ScottK  You wouldn't have a link to the log for that would you?
20:10   nixternal       I was just gonna ask, I have a lib I gotta package up :)
20:10   albert23
20:10   sistpoty        ScottK: sorry.. no idea if this is publically logged somewhere
20:10   sistpoty        thanks albert23
20:11   ScottK  albert23: Thanks
20:11   sistpoty        now in part 2, we'll be packaging a library by example, and will discuss a few of the caveats
20:12   sistpoty        since I'm lazy, let's take libmyhello again from part 1
20:12   sistpoty
20:13   sistpoty        everyone got it?
20:13   warp10  y
20:13   hellboy195      y
20:13   albert23        yep
20:13   sistpoty        ok, let's start with debianization... unpack it, rename the tarball so that we've got a valid .orig.tar.gz
20:14   sistpoty        let's take a look, we'll always need a few files in there, let's start with debian/copyright
20:16   sistpoty        put in the usual stuff there (this is not really important for the technical bits of library packaging)
20:17   sistpoty        what else do we need... I guess we'll be using debhelper, so let's create a compat in debian/
20:17   sistpoty        everyone got it so far?
20:17   hellboy195      y
20:17   warp10  y
20:18   albert23        y
20:18   sistpoty        ok, now let's start with the interesting bits
20:18   sistpoty        the control-file
20:19   sistpoty        First off comes the usual stuff (I'll pastebin this)
20:19   sistpoty        hm... pastebin is kinda slow today :(
20:20   sistpoty        ok, I'll paste it right here... pastebin doesn't like me *g*
20:21   sistpoty        Source: libmyhello
20:21   sistpoty        Section: libdevel
20:21   sistpoty        Priority: optional
20:21   sistpoty        Maintainer: Your Name <>
20:21   sistpoty        Build-Depends: debhelper (>> 5.0.0)
20:21   sistpoty        Standards-Version:
20:22   sistpoty        for a library, we'll always end up with two packages
20:22   sistpoty        two binary packages even
20:22   sistpoty        one package contains the shared object(s)
20:23   sistpoty        and another one, the -dev package will contain everything you need to develop applications with the shared object
20:24   sistpoty        i.e. header-files, eventually a statically linked library, eventually pkconfig files (which specify what to pass to the compiler/linker to link against this library)
20:25   sistpoty        so let's create an entry for the -dev package
20:25   sistpoty        Package: libmyhello-dev
20:25   sistpoty        Architecture: any
20:25   sistpoty        Description: myhello library headers
20:25   sistpoty        This package contains the development headers
20:25   sistpoty        for libmyhello.
* ScottK notes sistpoty needs to update to the current standards version...
20:26   sistpoty        ScottK: hehe, I'm not up to date
20:27   sistpoty        the package containing the shared object will need to be named in a special way:
20:28   sistpoty        it must be related to the soname.
20:28   sistpoty        the library packaging guide I mentioned contains the rules how it should be named
20:29   sistpoty        chapter 5, section 3
20:29   sistpoty        remember the soname of libmyhello yet?
20:30   sistpoty        anyone?
20:30   warp10  mmm..., maybe?
20:30   sistpoty        warp10: exactly
20:31   sistpoty        if you wouldn't have remembered, you could of course always use objdump -p <shared object> to find out
20:33   sistpoty        so in this case, the name of the library would be libmyhello1
20:33   sistpoty        if you've got a library, that contains more than one shared object
20:33   sistpoty        you'll need to create a binary package for each of these
20:33   sistpoty        let's add an entry for the binary package
20:34   sistpoty        Package: libmyhello1
20:34   sistpoty        Architecture: any
20:34   sistpoty        Depends: ${shlibs:Depends}
20:34   sistpoty        Description: myhello library
20:34   sistpoty        This package contains the hello library.
20:35   sistpoty        ok. anyone got a clue, why the name of this binary must be related to the SONAME?
20:35   sistpoty        this binary package...
20:36   sistpoty        anoyne`
20:36   sistpoty        +?
20:36   albert23        we want to be able to install multiple versions of the library, when ABI changes
20:36   sistpoty        albert23: excellent
20:37   sistpoty        so does anyone have an idea why this could be needed?
20:38   warp10  sistpoty: maybe different packages may need different versions of the library?
20:38   sistpoty        warp10: this would be one argument, but not the main one.
20:38   sistpoty        let's just consider that a very essential library (maybe libc) will get updated
20:39   sistpoty        currently, I've got libc6 installed, and I guess almost all packages I've got installed will depend on libc6
20:39   sistpoty        suddenly, a new libc7 appears
20:40   sistpoty        if it couldn't be installed side-by-side to libc6, that would mean that I had to remove *all* installed programs
20:40   sistpoty        or that all programs would immediately break if libc6 were removed by force
20:40   sistpoty        that's pretty bad, hm?
20:41   sistpoty        (I tried this once when I didn't have a clue... wasn't so funny back then *g*)
20:41   warp10  :)
20:41   sistpoty        any questions so far?
20:42   warp10  I have one
20:42   warp10  Why the -dev package doesn't need any Depends: field?
20:42   sistpoty        warp10: excellent question... it needs one :)
20:43   sistpoty        so, as I wrote earlier, the -dev package is what you install if you want to build programs using this library
20:44   sistpoty        so we need to make it depend at least on the library package
20:44   sistpoty        let's add the depends line there
20:45   sistpoty        the header files in question should always match what's in the shared object
20:45   sistpoty        hence we'll need to restrict the version for this dependency
20:46   sistpoty        Depends: libmyhello1 (= ${binary:Version})
20:47   sistpoty        however often you'll need additional libraries to compile a program with a specific library
20:47   sistpoty        so you'll need to add the corresponding -dev packages there as well.
20:48   sistpoty        a good indication should give you the NEEDED entries of the shared object
20:49   sistpoty        so you'll just need to find the corresponding -dev package that contains these shared objects
20:50   sistpoty        so, what do we need here?
20:51   albert23        NEEDED
20:51   sistpoty        great.
20:52   sistpoty        so let's find out in which package this is (we'll see a better method later)
20:52   sistpoty        just use dpkg -S
20:53   sistpoty        hooray, it's libc6 :)... so we'll want libc6-dev
20:54   sistpoty        (libc6-dev is often ommitted, since build-essential already depends on it. however it's not wrong to add it)
20:55   sistpoty        as you might have noticed, in the case of libc6, the -dev package is not named like the source package
20:55   sistpoty        but instead it is named like the binary package + -dev
20:56   sistpoty        this is useful, if you want to have more than just one version of the library in the archive
20:56   sistpoty        (e.g. because one application needs the old one, and won't build with the new version)
20:56   sistpoty        then you'll need to be able to select which -dev package you want
20:57   ScottK  There's a very recent thread on adding libc6 on debian-devel that came down pretty strongly in favor of adding it.
20:57   sistpoty        if you do this, you should have the -dev package(s) of the different versoin Provide and Conflict to libmyhello-dev package
20:58   sistpoty        ScottK: ah, haven't read that one yet
20:58   sistpoty        (or maybe I have but forgot *g*)
20:59   sistpoty        ok, does everyone have the control file so far?
20:59   albert23        y
20:59   warp10  y
21:00   sistpoty        hehe, mine is still missing the depends line *g*
21:01   sistpoty        ok
21:01   sistpoty        what else do we need... a changelog file. just create one with dch
21:03   sistpoty        dch --create
21:03   sistpoty        (needed to look this up, thought it always was -c)
21:04   sistpoty        everyone got it filled in?
21:04   warp10  y
21:05   albert23        y
21:05   sistpoty        ok, then let's start with the rules file
21:06   sistpoty        let's see what targets we need to adhere to the policy: clean, build, binary, binary-arch, binary-indep
21:06   sistpoty        did I miss one?
21:07   warp10  install?
21:07   ScottK  configure?
21:07   slangasek       not required by policy :)
21:07   sistpoty        yep
21:07   warp10  configure should be optional, right?
21:07   sistpoty        hi slangasek btw.
* slangasek waves
21:08   warp10  install is optional too?
21:08   sistpoty        warp10: libmyhello fortunately doesn't need to be configured, as it doesn't use autotools
21:08   sistpoty        warp10: yes
21:09   sistpoty        let's start with clean, should be easiest
21:09   sistpoty        since we'll use debhelper, we'll first call dh_clean
21:09   sistpoty        and then: make clean
21:09   sistpoty        to cleanup libmyhello stuff
21:09   sistpoty        or, if you prefer make distclean
21:10   sistpoty        (which won't make a difference *here*)
21:12   sistpoty        then let's get a shot at the build rule
21:12   james_w sistpoty: dh_testroot to start clean as well?
21:13   sistpoty        james_w: right, makes sense
21:14   sistpoty        ok, build should be easy as well.
21:14   sistpoty        just a call to make
21:14   sistpoty        any questions so far?
21:15   warp10  n
21:15   albert23        n
21:15   sistpoty        ok, then let's go to the binary target
21:16   sistpoty        since this is an arch:any package, we'll use the binary-arch target for the job, and have the binary target depend on it
21:17   sistpoty        let's add some debhelper stuff
21:18   sistpoty        dh_testdir
21:18   sistpoty        dh_testroot
21:18   sistpoty        dh_installchangelogs
21:18   sistpoty        dh_installdocs
21:19   sistpoty        dh_install
21:19   sistpoty        dh_strip
21:19   sistpoty        dh_compress
21:19   sistpoty        dh_fixperms
21:20   sistpoty        and now an interesting one: dh_makeshlibs
21:20   sistpoty        (we'll have a look at it in a few minutes)
21:20   sistpoty        dh_shlibdeps
21:20   sistpoty        dh_installdeb
21:20   sistpoty        dh_gencontrol
21:20   sistpoty        dh_md5sums
21:20   sistpoty        dh_builddeb
21:21   sistpoty        since we'll need to build before we can install it, we'll add a dependency to build for binary-arch
21:22   sistpoty        (a nicer way is to use stamps, but that's a different topic)
21:22   sistpoty        now what does dh_makeshlibs do...
21:23   sistpoty        as you may have noticed, whenever you put ${shlibs:Depends} in the control file, it will get resolved to the library packages during build
21:23   sistpoty        this is done via the shlibs-mechanism
21:23   sistpoty        if you've been here in part 1, I guess you could build one yourself
21:24   sistpoty        if you look at /var/lib/dpkg/info, you'll find a number of shlibs-files
21:25   sistpoty        let's take a look at one
21:26   sistpoty        the format is: library-name soname-version dependencies
21:27   sistpoty        let's look at /usr/lib/dpkg/info/libgnome2-0.shlibs
21:28   sistpoty        compare this to the SONAME of /usr/lib/
21:28   sistpoty        this explains the first two fields
21:29   sistpoty        the third one is the package where this shared object can be found in
21:29   sistpoty        the job of dh_makeshlibs is to generate such a file for us
21:29   warp10  cool...
21:31   sistpoty        and at this point, we can try to answer mok0's question of part 1, what to do if upstream released a new abi compatible version, but programs use this one
21:31   sistpoty        since the shlibs file can specify a version string (just look at the gnome shlibs file again)
21:31   sistpoty        we can request to have a minimum version of the library
21:32   sistpoty        this will get replaced for all packages that use ${shlibs:Depends} and build against our library
21:33   sistpoty        so we only need to tell dh_makeshlibs, that a new feature landed in the library, so that it will set version field in the shlibs file right
21:33   sistpoty        you can do this with dh_makeshlibs -V<version>
21:33   sistpoty        now if anyone has installed an older version of the library, and wants to use the program that needs the new cool features
21:34   sistpoty        he will have to upgrade the library via apt
21:34   sistpoty        any questions so far?
21:34   albert23        How can we know which library version was the first providing a specific ABI version?
21:35   albert23        Isn't there a risk we set version to high in dh_makeshlibs -V<version>?
21:35   sistpoty        albert23: pretty much through the same means that we can find out if the ABI is broken
21:35   albert23        ok
21:36   sistpoty        albert23: there is no real risk in Ubuntu to set the version to high
21:36   sistpoty        however setting the version not high enough can lead to problems
21:36   albert23        It would make backports more difficult?
21:37   sistpoty        not too sure... I don't think so
21:37   sistpoty        a backport gets compiled to whatever is in gutsy or feisty
21:37   sistpoty        so it will get built against the feisty/gutsy version of the library, which has a different version requirement
21:37   ScottK  So if you set it correctly and there isn't a sufficient ABI available, the backport build will, correctly, fail.
21:38   sistpoty        well... it doesn't really relate to building, but rather to installin
21:38   sistpoty        +g
21:39   sistpoty        in order to build against a library, the version (and ABI) is irrelevant.
21:39   sistpoty        what matters to build against it is the API
21:39   sistpoty        the version rather enforces that users *need* to upgrade the library to a minimum ABI version
21:39   ScottK  I guess I meant API then.
21:40   sistpoty        so if the API changed, the field won't really be much of a problem, since this means a new ABI in almost all cases
21:40   sistpoty        and hence a new SONAME, and a different library package
21:41   sistpoty        this version is only relevant if the ABI/API stay the same, but new features got added
21:41   ScottK  Ah.  RIght.
21:41   sistpoty        any further questions?
21:42   warp10  n
21:42   albert23        n
21:42   sistpoty        ok, then let's try to fix the rules file and finish the package, shall we?
21:43   sistpoty        since we use dh_install, we still need to install the files into debian/tmp/
21:43   sistpoty        let's use PREFIX=$(pwd)/debian/tmp make install for this
21:44   sistpoty        if you want, you can put this right at the beginning of binary-arch
21:44   sistpoty        or you could add an install rule and have binary-arch depend on it... whatever you prefer
21:46   sistpoty        now we'll need to sort which files go into which package
21:47   sistpoty        so we want libmyhello1.install and libmyhello-dev.install
21:47   sistpoty        the header files will go into the -dev package
21:49   sistpoty        bah... back a few lines... (recalled the Makefile wrongly)... PREFIX should of course be $(pwd)/debian/tmp/usr
21:49   sistpoty        I guess I should have added DESTDIR or to libmyhello's makefile
21:50   sistpoty        in case we'd have a statically linked library (libmyhello.a), that would go into the -dev package as well.
21:51   sistpoty        (only useful if you want to link statically against it)
21:52   sistpoty        what else do we need in the -dev pacakge
21:52   sistpoty        the .so symlink should go in there as well
21:53   sistpoty        btw: the .so symlink is what the linker will look for if you give the -l parameter
21:53   sistpoty        more specifically, if you'd call -lmyhello, it would prepand a lib and add an .so and look for this file (
21:54   sistpoty        in case there are any other files for development purposes (pkconfig files for example), these should also go in the -dev package
21:54   sistpoty        luckily we don't have these
21:56   sistpoty        in the library package should be the shared object (of course) and the symlink that's named like the soname
21:56   sistpoty        while the symlink itself would also be recreated by ldconfig
21:57   sistpoty        including it in the library package has the advantage that it will get deleted if the library is removed
21:57   sistpoty        because it's a file of the package
21:58   sistpoty        everyone got the .install files?
21:58   albert23        y
21:58   warp10  y
21:59   sistpoty        ok, let's give it a shot, and see if it works
21:59   sistpoty        just use
21:59   sistpoty        fakeroot make -f debian/rules binary
22:00   sistpoty        to fix the errors
22:00   sistpoty        (like my install files, that where wrong *g*)
22:00   albert23        mine too
22:00   warp10  argh... :-S
22:01   sistpoty        did you fix the PREFIX=... make install?
22:01   albert23        y
22:01   warp10  sistpoty: just a wrong install for me too :)
22:01   sistpoty        warp10: hehe
22:04   albert23        I think $(pwd) did not work
22:04   albert23        make tried to install in /debian
22:05   sistpoty        it should install into debian/tmp/usr/
22:05   albert23        I got this: PREFIX=/debian/tmp/usr make install
22:06   sistpoty        heh, I've got the same which doesn't work as well. but the answer is one line above
22:06   sistpoty        PREFIX=debian/tmp/usr make install
22:06   sistpoty        those nasty slashes *g*
22:06   warp10  grrrr
22:06   albert23        Yep, just removed the pwd part, that works
22:09   sistpoty        hm... I guess I'll need to read the make manual again, I was so sure that $(PWD) exists (or $(pwd))
22:09   albert23        $(CURDIR) ?
22:09   slangasek       $(PWD) exists only if it's set in the environment by the invoking shell
22:10   slangasek       $(shell pwd) execs out to call the pwd command, so is rather inefficient
22:10   slangasek       $(CURDIR) is the make builtin variable you should use
22:11   sistpoty        thanks... I guess I confused this with $(pwd), which I often type in the shell *g*
22:11   slangasek       :)
22:11   sistpoty        so does everyone's build succeed now?
22:12   albert23        yep, package looks good
22:12   warp10  looks fine!
22:12   sistpoty        damn, only mine doesn't build yet *g*
22:13   sistpoty        ok, so you've got a source package and a binary
22:13   sistpoty        let's run lintian at the binary packages. it will take a second look that we've got the files sorted out correctly
22:14   albert23        clean
22:15   sistpoty        excellent!
22:15   sistpoty        any questions so far?
22:16   albert23        no, that's pretty clear
22:17   warp10  it's fine. Just wondering if it would be so easy in the real-world packaging :)
22:18   albert23        I guess that strongly depends on upstream
22:18   sistpoty        ok, so now what would you do if the ABI of a library changed, but the SONAME didn't?
* slangasek smiles
22:19   albert23        complain at upstream
22:19   sistpoty        albert23: great, that should always be the first choice
22:19   sistpoty        can you imagine, while it's a bad idea, if you bump the SONAME on your own?
22:20   sistpoty        (as a packager)?
22:20   albert23        could be risky, as it might conflict with new upstream versions?
22:21   sistpoty        that's one argument
22:22   sistpoty        but you could append a debian or ubuntu somewhere and change the build scripts, so you could circumvent this
22:22   sistpoty        any other arguments against this?
22:22   slangasek       it leads to binary incompatibility with other distros
22:22   slangasek       but that shouldn't outweigh the problems caused by binary incompatibility with previous releases
22:23   sistpoty        also, it leads to binary incompatibility for binary only software
22:23   sistpoty        (just imaging to change the SONAME of libc, and look at what breaks in multiverse)
22:24   slangasek       well, a workaround for such binary-only software would be to instruct users to create their own local symlinks for the wrong soname
22:25   sistpoty        heh
22:25   sistpoty        ok, what other interesting points do we have...
22:25   slangasek       like I said, the alternative is that you have to break all the /free/ software using the old version on upgrade :)
22:25   sistpoty        yeah, it's either bad or worse *g*
22:26   sistpoty        ok, what should you do when you upgrade a library?
22:26   slangasek       by "upgrade", you mean "package a new version"?
22:26   sistpoty        yes
22:27   sistpoty        we already learned that we should look out for ABI compatibility, so let's look at the case where we *do* have a new SONAME
22:27   sistpoty        and hence a new library package
22:28   sistpoty        anyone any ideas?
22:28   slangasek       grep -r $oldsover debian/ :)
22:28   albert23        I think we are going to have a problem with the -dev package
22:29   sistpoty        albert23: what do you think could get problematic?
22:29   albert23        packages requiring the old ABI will get the new ABI when we would want to rebuild?
22:30   sistpoty        exactly (but it's API in this case... compiling *P*rograms->aPi, binaries->aBi)
22:31   sistpoty        so you should check which packages actually build-depend on the -dev package.
22:31   sistpoty        if there is a large number, you could do local test-builds and see which fail
22:32   sistpoty        in case you cannot live yet with the new version alone, you could for example make a different source package and hence have two version of the library in the archive
22:33   sistpoty        one thing you might stumble over when dealing with libraries is a lintian warning about rpath
22:34   sistpoty        when you link against a library, that has an rpath set, it will tell the loader to look for the shared object only in that very directory
22:34   sistpoty        so you can specify -Wl,-rpath=/somewhere and link hello_prog against it
22:35   sistpoty        then the loader will look for libmyhello only in /somewhere when hello_prog is started
22:35   sistpoty        can anyone imagine, why using rpath for a library is a bad idea?
22:38   albert23        well, software would break if for some reason the library is moved to another directory....
22:38   sistpoty        exactly
22:38   sistpoty        and one use-case for moving a library is for example the ia32-libs package on amd64
22:39   sistpoty        ok, any questions?
22:39   slangasek       (and multiarch! whoo!)
22:40   slangasek       albert23, sistpoty: I would note that the general case is that we don't want to continue supporting an old API for a library, even if it means some work has to be done to get the applications ported
22:40   slangasek       so it's /usually/ better to have the new library version take over the source package name and the -dev package name, and only reintroduce an oldlibs package as a last resort
22:41   sistpoty        thanks for clarifying
22:41   albert23        Well, one question: what would be the best place to look for bugs / qa issues to practice what we learned?
22:42   sistpoty        hm... that's a good question indeed
22:42   sistpoty        well, one thing is that you could review library packages on REVU
22:43   sistpoty        or get your hands dirty and package a library
22:44   sistpoty        ok, I guess we're through with the session... slangasek: anything important I forgot or you'd like to add?
22:45   slangasek       sistpoty: I only had half an eye on the channel today; I guess you didn't talk about techniques maintainers can use to automatically detect ABI breakage when moving to a new upstream version?
22:45   sistpoty        slangasek: nope
22:46   slangasek       the dpkg in hardy includes the new dpkg-gensymbols code developed by Raphaƫl Hertzog in Debian; it basically creates a manifest, declaring which symbols were added in which version of the package
22:46   slangasek       the /side/ benefit of this is that if you already know which symbols are supposed to be present, you know if any have gone missing
22:47   slangasek       so is a site that includes automatically generated symbol manifests for all libs in the archive
22:47   slangasek       (the Debian archive, that is; most will be applicable to Ubuntu too, obviously)
22:48   slangasek is a general description of this
22:48   slangasek       I still need to use this on my own packages, so I can only give you theoretical insight into this stuff, not much practical :)
22:49   slangasek       and everyone's eyes glaze over again ;)
22:50   albert23        Yeah, I guess I will first do some attempts to do the work manually.
22:50   albert23        I have bookmarked those links for later use...
22:51   slangasek       one example of this in practice is the zlib1g package
22:51   slangasek       which the maintainer, Mark Brown, blogged about as well (syndicated on planet.d.o)
22:52   sistpoty        heh, I skipped this post, and wanted to read it later (which I then forgot *g*)
22:52   sistpoty        ok, anything else?
22:53   sistpoty        then thanks everyone for coming :)

This log has been lightly edited for clarity.

MOTU/School/LibraryPackaging (last edited 2008-08-06 16:33:17 by localhost)