Most of those tips are great, but dont use autotools! The points they give for choosing autotools are exactly the same as one would have read maybe a decade ago when people said that CVS was "good enough" and that it "just works." Subversion, git and several others are much better alternatives and where developed because people weren't happy with CVS quirks and crappiness. One example is waf (http://docs.waf.googlecode.com/git/book_16/single.html), arguably just as well documented as autotools but without all the cruft and generated files madness autotools forces you to go through. CMake (http://www.cmake.org/) is another, used by KDE 4. SCons (http://www.scons.org/) another nice build tool. These also have the advantage of working much better on Windows, a platform autotools is completely alien to.
Eh, if it's a C library, use autotools. Really, the original article says it best:
- We are all used to autotools, it works, nobody cares.
...
- And really, anything but autotools is realy an option. Just get over it.
Everything else is an experiment, and it will come back
to you sooner or later. Why? think cross compilation, installation/
uninstallation, build root integration, separate object trees,
standard adherence, tarball handling, make distcheck, testing,
portability between distros, ...
Please do use autotools! You only need two files: configure.ac and Makefile.am, both at the top-level of your project. The autogenerated stuff can be ignored, you don't have to learn M4 to use autoconf. And (if you are a bit careful, but that's not too hard) you'll have many nice features such as out-of-source builds, proper feature checking, amazing portability, 'make distcheck', and acceptable cross-compiling (still hard to get right, but the alternatives tend to be even harder). Don't switch to another build system purely based on the idea that it's "more elegant".
I rather dislike autotools (every time I wait for a configure file to make a million compiler tests which could be stored in a global cache, it's wasting my time), but I wish some of the alternative build tools placed a higher priority on being compatible with it rather than inventing their own syntax. If I want to do something like cross compile or even just add custom cflags (ugh, cmake...), I know what configure option will do so, and it's not a particularly bad interface either. From a user's perspective, build systems are usually boring; a consistent user interface makes the world a little simpler.
I know some folks like it in all it's python-y glory, but I found it opaque and horrible. Finding where things are done and how to change its behaviour was surprisingly hard work. Now this may have been at least partly due to the way the project was set up but... well just give me a nice Makefile any day.
As someone who's done a bit of Debian development, I find autotools packages a lot easier to deal with than the alternatives. It might be a bit crufty, but if used properly it works very well.
OK, there are a lot of autoconf scripts that are poorly written, and therefore don't get the benefits. I've never heard of waf. I've never had to fight with scons, but I've never used it for my project.
But, for the love of all that is holy, do not CMake. It works fantastically... until you have to fix something. I tell you this as a distro packager. I've had to fight with build systems. Patching autoconf files, automake files, ant files, are all fairly comfortable for me. I dread the days when I have to figure out an issue with CMake.
CMake is a nightmare on OS X, especially if you have Homebrew installed. If you're wanting to go down this route, gyp is a much better choice, though still rather new.
This is good advice especially if you want to write bindings for other languages, including callbacks (as I've found) adds a lot of difficulty to that stage.
However, two main projects I work on use callbacks extensively. The reason is that they are essentially event-based, and it would seem much less user-friendly to force the user to implement a huge switch statement, particularly when user-defined events are involved.
How else could callbacks be avoided? In some cases, they just seem like the most user-friendly option.
Although for bindings they are more difficult, using callbacks can be great when binding to higher-level languages, where the user can specify what should happen using a short lambda function (e.g. Python, etc.) A switch statement or whatever is much more obnoxious in those cases, so what other solutions are there?
Interfaces like epoll let you pass and return you a 64 bit value which can be an address of a callback or a value to look up in a dispatch table. The user can choose. This is very flexible.
I believe the OP is about "the library" as something giving some functionality that you add to your project in whatever way it can be added, not as something you must dynamically link.
I also agree that there are use cases where static linking solves some problems.
Nice set of tips. I'd like to put an emphasis on symbol versioning, SONAMEs and symbol visibility. That's what allows distribution to upgrade your library without recompiling everything, and too few developers are aware of this (simple) mechanism.
The solution I have done in my software is to close all unneeded file descriptors right after fork() in the child [1].
It can be argued that this is not the best solution because every place where fork() is called needs to be patched, and this could be in libraries. But the same applies to O_CLOEXEC flags; every place where file descriptors are created needs to be patched. Further, there are probably many more places where fd's are created than where fork() is called.
So if you want to be super careful library, you should do both. Yes, I know the article advises against fork() from libraries. But sometimes you really need it. It's not bad per-se, just bad when done in *nix because of the broken design of OS interfaces.
No, seriously, please just use autotools. It's way better for users and packagers of your library.
If you're not going to do that, then use an alternative that provides the same command-line interface as autotools (so that things like "./configure --prefix=FOO && make -j4 && make install DESTDIR=BAR" still work). As far as I know, there's no such thing as of yet.
Don't do your own locking. Let the caller pass in state. Push locking to the caller. Don't have your own global state that would need hidden locks, but instead let the caller handle it with arguments.
That is similar how the STL does it, but not like stdio
I'm not sure I fully agree.
- For simple libraries it's likely good advice.
- But it encourages big locks and poor scaling. It may be right for desktop apps, but not necessarily for server code that needs to scale. For some things that's fine, but you don't want that for the big tree or hash table that your multi threaded server is built around on.
- It avoids the problems of locks being non composable, that is the caller may need to know which order the locks need to be called, to avoid deadlock. Actually it doesn't avoid it, just pushes it to someone else.
However if you make sure the library is always the leaf and never calls back the library locks will be generally at the bottom of the lock hierarchy.
[+] [-] bjourne|13 years ago|reply
[+] [-] anonymouz|13 years ago|reply
[+] [-] yorhel|13 years ago|reply
[+] [-] comex|13 years ago|reply
[+] [-] Nursie|13 years ago|reply
I know some folks like it in all it's python-y glory, but I found it opaque and horrible. Finding where things are done and how to change its behaviour was surprisingly hard work. Now this may have been at least partly due to the way the project was set up but... well just give me a nice Makefile any day.
[+] [-] pdw|13 years ago|reply
[+] [-] LukeShu|13 years ago|reply
But, for the love of all that is holy, do not CMake. It works fantastically... until you have to fix something. I tell you this as a distro packager. I've had to fight with build systems. Patching autoconf files, automake files, ant files, are all fairly comfortable for me. I dread the days when I have to figure out an issue with CMake.
[+] [-] iambvk|13 years ago|reply
Doing complex dependencies in CMake is a pain where as with Autmake, I can just go back to Make in the same file.
[+] [-] antirez|13 years ago|reply
[+] [-] jahewson|13 years ago|reply
[+] [-] radarsat1|13 years ago|reply
This is good advice especially if you want to write bindings for other languages, including callbacks (as I've found) adds a lot of difficulty to that stage.
However, two main projects I work on use callbacks extensively. The reason is that they are essentially event-based, and it would seem much less user-friendly to force the user to implement a huge switch statement, particularly when user-defined events are involved.
How else could callbacks be avoided? In some cases, they just seem like the most user-friendly option.
Although for bindings they are more difficult, using callbacks can be great when binding to higher-level languages, where the user can specify what should happen using a short lambda function (e.g. Python, etc.) A switch statement or whatever is much more obnoxious in those cases, so what other solutions are there?
[+] [-] justincormack|13 years ago|reply
[+] [-] qznc|13 years ago|reply
Most prominently Plan9 and friends are opposed to dynamically linked libraries.
[+] [-] emillon|13 years ago|reply
[+] [-] acqq|13 years ago|reply
I also agree that there are use cases where static linking solves some problems.
[+] [-] mhd|13 years ago|reply
It also doesn't really work out if you're not buying that philosophy as a whole.
[+] [-] emillon|13 years ago|reply
[+] [-] jfaucett|13 years ago|reply
[+] [-] VMG|13 years ago|reply
One of the authors of the linked piece is Lennart Poettering, creator of PulseAudio
[+] [-] aerique|13 years ago|reply
[+] [-] chj|13 years ago|reply
[+] [-] andrewcooke|13 years ago|reply
[+] [-] ambrop7|13 years ago|reply
It can be argued that this is not the best solution because every place where fork() is called needs to be patched, and this could be in libraries. But the same applies to O_CLOEXEC flags; every place where file descriptors are created needs to be patched. Further, there are probably many more places where fd's are created than where fork() is called.
So if you want to be super careful library, you should do both. Yes, I know the article advises against fork() from libraries. But sometimes you really need it. It's not bad per-se, just bad when done in *nix because of the broken design of OS interfaces.
[1] http://code.google.com/p/badvpn/source/browse/trunk/system/B...
[+] [-] meaty|13 years ago|reply
Thats a sign something needs to be taken out in the yard and shot if there ever was one.
[+] [-] dlitz|13 years ago|reply
If you're not going to do that, then use an alternative that provides the same command-line interface as autotools (so that things like "./configure --prefix=FOO && make -j4 && make install DESTDIR=BAR" still work). As far as I know, there's no such thing as of yet.
[+] [-] sigjuice|13 years ago|reply
[+] [-] olalonde|13 years ago|reply
Can anyone explain this piece of advice?
[+] [-] nn2|13 years ago|reply
That is similar how the STL does it, but not like stdio
I'm not sure I fully agree. - For simple libraries it's likely good advice. - But it encourages big locks and poor scaling. It may be right for desktop apps, but not necessarily for server code that needs to scale. For some things that's fine, but you don't want that for the big tree or hash table that your multi threaded server is built around on. - It avoids the problems of locks being non composable, that is the caller may need to know which order the locks need to be called, to avoid deadlock. Actually it doesn't avoid it, just pushes it to someone else. However if you make sure the library is always the leaf and never calls back the library locks will be generally at the bottom of the lock hierarchy.
[+] [-] andrewcooke|13 years ago|reply
[deleted]