| /* | |
| This is free and unencumbered software released into the public domain. | |
| Anyone is free to copy, modify, publish, use, compile, sell, or | |
| distribute this software, either in source code form or as a compiled | |
| binary, for any purpose, commercial or non-commercial, and by any | |
| means. | |
| In jurisdictions that recognize copyright laws, the author or authors | |
| of this software dedicate any and all copyright interest in the | |
| software to the public domain. We make this dedication for the benefit | |
| of the public at large and to the detriment of our heirs and | |
| successors. We intend this dedication to be an overt act of | |
| relinquishment in perpetuity of all present and future rights to this | |
| software under copyright law. | |
| Unless you really want to, do not even mention that the copied content | |
| originates from this skeleton library. Its sole purpose is to be copied | |
| into other projects. | |
| The above statements apply to all content in this skeleton library, even | |
| when the COPYING files, or the headers in the files state otherwise, | |
| they are just common examples. | |
| */ | |
| Questions, feedback, patches please email: | |
| systemd-devel@lists.freedesktop.org (subscriber-only) | |
| or: | |
| Kay Sievers <kay@vrfy.org> | |
| Lennart Poettering <lennart@poettering.net> | |
| Why bother? | |
| - To make things easy for library users, distribution packagers and | |
| developers of library bindings for other programming languages. If | |
| you want your stuff to be used and commonly available, try to play | |
| nice, and give them what they are used to. It makes their life a | |
| lot easier. | |
| Use autotools | |
| - Every custom config/makefile/build system is worse for everybody | |
| than autotools is. | |
| - We are all used to autotools, it works, nobody cares. | |
| - It's only two simple files to edit and include in git, which are | |
| well understood by many many people, not just you. | |
| - Ignore all crap autotools create in the source tree. Never check | |
| the created files into git. | |
| - Never, ever, install config.h. That's internal to your sources | |
| and is nothing to install. | |
| - And really, nothing but autotools is really 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, ... | |
| If you use the GPL, always use the GPL's "(or later)" clause | |
| - Developers are not lawyers, libraries should be able to be linked | |
| to any version of the GPL. Remember that GPL2-only is incompatible | |
| with LGPL3! | |
| Use LGPL (for the shared libraries) if you don't care about politics | |
| - It protects the code, but does not restrict its use. Low-level | |
| library interfaces are mostly used like kernel syscall or proc/sysfs | |
| interfaces, which are usually without any restrictions. | |
| Zero global state -- Make your library threads-aware, but *not* thread-safe! | |
| - An app can use liba and libb. libb internally can also use liba -- | |
| without you knowing. Both you and libb can run liba code at the | |
| very same time in different threads and operate at the same global | |
| variables, without telling you about that. Loadable modules make | |
| this problem even more prominent, since the libraries they pull in | |
| are generally completely unknown by the main application. And | |
| *every* program has loadable modules, think NSS! | |
| - Avoid locking and mutexes, they are very unlikely to work correctly, | |
| and incredibly hard to get right. | |
| - Always use a library context object. Every thread should then | |
| operate on its own context. Do not imply context objects via TLS. It | |
| won't work. TLS inheritance to new threads will get in your way. TLS | |
| is a problem in itself, not a solution. | |
| - Do not use gcc constructors, or destructors, you can only lose if | |
| you do. Do not use _fini() or _ini(), don't even use your own | |
| explicit library initializer/destructor functions. It just won't | |
| work if your library is pulled in indirectly from another library | |
| or even a shared module (i.e. dlopen()) | |
| - Always use O_CLOEXEC, SOCK_CLOEXEC and friends. It's not an | |
| option, it's a must. | |
| - Don't use global variables (it includes static variables defined | |
| inside functions). Ever. And under no circumstances export global | |
| variables. It's madness. | |
| Use a common prefix for _all_ exported symbols | |
| - Avoids namespace clashes | |
| - Also, hacking is not a contest of finding the shortest possible | |
| function name. And nobody cares about your 80ch line limit! | |
| - If you use a drop-in library in your own library make sure to hide its | |
| symbols with symbol versioning. Don't forget to hide *all* symbols, and | |
| don't install the header file of the used drop-in library. | |
| Do not expose any complex structures in your API | |
| - Use get() and set() instead. | |
| - All objects should be opaque. | |
| - Exporting structs in headers is OK in very few cases only: usually | |
| those where you define standard binary formats (think: file | |
| formats, datagram headers, ...) or where you define well-known | |
| primitive types (think struct timeval, struct iovec, uuid | |
| type). | |
| - Why bother? Because struct stat, struct dirent and friends are | |
| disasters. Particularly horrible are structs with fixed-size | |
| strings. | |
| Use the de-facto standardized function names | |
| - It's abc_new(), abc_free(), abc_ref(), abc_unref(). Don't invent | |
| your own names, and don't use the confusing kernel-style ref | |
| counting. Function names: _get() is for accessing properties of | |
| objects, not for refcounting. | |
| Stick to kernel coding style | |
| - Just because you are otherwise not bound by the kernel guidelines | |
| when your write userspace libraries doesn't mean you have to give | |
| up the good things it defines. | |
| Avoid callbacks in your API | |
| - Language bindings want iterators. | |
| - Programmers want iterators too. | |
| Never call exit(), abort(), be very careful with assert() | |
| - Always return error codes. | |
| - Libraries need to be safe for usage in critical processes that | |
| need to recover from errors instead of getting killed (think PID 1!). | |
| Avoid thinking about main loops/event dispatchers. | |
| - Get your stuff right in the kernel: fds are awesome, expose them | |
| in userspace and in the library, because people can easily integrate | |
| them with their own poll() loops of whatever kind they have. | |
| - Don't hide file descriptors away in your headers. | |
| - Never add blocking kernel syscalls, and never add blocking library | |
| calls either (with very few exceptions). Userspace code is primarily | |
| asynchronous around event loops, and blocking calls are generally | |
| incompatible with that. | |
| - Corollary of that: always O_NONBLOCK! | |
| Functions should return int and negative errors instead of NULL | |
| - Return NULL in malloc() is fine, return NULL in fopen() is not! | |
| - Pass allocated objects as parameter (yes, ctx_t** is OK!) | |
| - Returning kernel style negative <errno.h> error codes is cool in | |
| userspace too. Do it! | |
| Provide pkgconfig files | |
| - Apps want to add a single line to their configure file, | |
| they do not want to fiddle with the parameters, dependencies | |
| to setup and link your library. | |
| - It's just how we do these things today on Linux, and everything | |
| else is just horribly messy. | |
| Avoid *hidden* fork()/exec() in libraries | |
| - Apps generally do not expect signals and react allergic to them. | |
| - Mutexes, locks, threads of the app might get confused. Mixing | |
| mutexes and fork() equals failure. It just can't work, and | |
| pthread_atfork() is not a solution for that, because it's broken | |
| (even POSIX acknowledges that, just read the POSIX man | |
| pages!). fork() safety for mutex-ridden code is not an | |
| afterthought, it's a broken right from the beginning. | |
| Make your code safe for unexpected termination at any point: | |
| - Do not leave files dirty or temporary files around. | |
| - This is a tricky, since you need to design your stuff like this | |
| from the beginning, it's not an afterthought, since you generally | |
| do not have a place to clean up your stuff on exit. gcc | |
| destructors are NOT the answer. | |
| Use symbol versioning | |
| - Only with that, RPM can handle dependencies for added symbols | |
| - Hide all internal symbols! *This is important!* | |
| Always provide logging/debugging, but do not clutter stderr | |
| - Allow the app to hook the libs logging into its logging facility. | |
| - Use conditional logging, do not filter too late. | |
| - Do not burn cycles with printf() to /dev/null. | |
| - By default: do not generate any output on stdout/stderr. | |
| Always use 'make distcheck' to create tarballs | |
| - Never release anything that does not pass distcheck. It will | |
| likely be broken for others too | |
| Use ./autogen.sh to bootstrap the git repo | |
| - Always test bootstrapping with 'git clean -x -f -d' before | |
| release (careful, it force-deletes all uncommitted files). | |
| Avoid any spec files or debian/ subdirs in git trees | |
| - Distribution specific things do not belong in upstream trees, | |
| but into distro packages | |
| Update NEWS to let developers know what has changed | |
| - It's the history of the project, stuff that packagers need to know | |
| when putting a new version in the distro. The interesting changes | |
| or added/removed functionality from version to version. This is | |
| not a commit changelog. | |
| - If you want to provide ChangeLog, use the one generated | |
| by git, do not maintain your own. | |
| Use standard types | |
| - The kernel's u8, u16, ... correspond to uint8_t, uint16_t in | |
| userspace from <inttypes.h>. Don't define your own typedefs | |
| for that, don't include the kernel types in common headers. | |
| - Use enums, not #define for constants, wherever possible. In | |
| userspace you have debuggers, and they are much nicer to use if | |
| you have proper enum identifiers instead of macro definitions, | |
| because the debugger can translate binary values back to enum | |
| identifiers, but not macros. However, be careful with enums in | |
| function prototypes: they might change the int type they are | |
| resolved to as you add new enum values. | |
| Always guard for multiple inclusions of headers | |
| - You must place '#ifndef libabc, #define libabc, #endif' in your | |
| header files. There is no way around that. | |
| Be careful with variadic functions | |
| - It's great if you provide them, but you must accompany them with | |
| "v" variants (i.e. functions taking a va_arg object), and provide | |
| non-variadic variants as well. This is important to get language | |
| wrappers right. | |
| Don't put "extern" in front of your function prototypes in headers | |
| - It has no effect, no effect at all. | |
| Never use sysv IPC, always use POSIX IPC | |
| - Shmops and semops are horrors. Don't use them, ever. POSIX IPC is | |
| much much much nicer. | |
| Avoid multiplexed functions ala ioctl()/prctl() style variadic functions | |
| - Type-safety is awesome! | |
| Executing out-of-process tools and parsing their output is usually | |
| not acceptable in libraries | |
| - Tools should be built on top of their own lib. | |
| - Always separate 'mechanism' from 'policy'. Make access to functionality | |
| simple, but do not try to hide things that need to be decided by the | |
| caller. Keep automagic at its minimum. Don't do hidden fork() do not | |
| implicitly maintain cache files, ... | |
| Function calls with 15 arguments are a bad idea. If you have tons of | |
| booleans in a function call, then replace them by a flag argument! | |
| - Think about the invocation! foo(0, 1, 0, 1, 0, 0, 0, 1) is unreadable! | |
| foo(FOO_QUUX|FOO_BAR|FOO_WALDO) much nicer. | |
| Don't be afraid of C99. Use it. | |
| - It's 12 years old. And it's nice. | |
| Never expose fixed size strings in your API | |
| - Pass malloc()ed strings out, or ask the caller to provide you with | |
| a buffer, and return ENOSPC if too short. | |
| Glibc has byteswapping calls, don't invent your own: | |
| - le32toh(), htole32() all those are documented in endian(3) | |
| - bswap_32(), bswap_16(), bswap_64(). #include <byteswap.h> | |
| - Don't use the versions provided by the linux kernel headers cpu_to_*() , *_to_cpu. | |
| stick to the glibc API. | |
| Don't typedef pointers to structs! | |
| Don't write your own LISP interpreter and do not include it in your | |
| library. :) |