In the case when these routines are required (as they are in ncurses) there is an easier way to provide the proper setup without placing the onus to call these methods on the developer. GCC provides __attribute__((constructor)) and __attribute__((destructor)) which allow for calling methods when a library is loaded and unloaded respectively. These calls happen outside the scope of main. For example,
#include <stdio.h>
__attribute__((constructor)) void init() {
fprintf (stderr, "constructor\n");
}
int main () {
return fprintf(stderr, "main\n");
}
This program will output the following:
constructor
main
In the case of a library such as ncurses this is a perfect place to invoke the necessary initialization and cleanup routines. A simplified example library:
__attribute__((constructor))
static void setup() { do_some ("setup"); }
__attribute__((destructor))
static void breakdown() { do_some ("breakdown"); }
void mylib_method (const char * thing) { do_some (thing); }
Now, if a developer links against your library setup() is called when your library is loaded and breakdown() is called when it is unloaded. A nicety of this approach is that it provides the same functionality if the library is pulled in when the executable is loaded or at some later point (via dlopen/dlsym, for example) thus always ensuring a consistent environment for your code.
This is obviously not a fit for all libraries. Only those with setup and cleanup that can be self-contained and are always required would benefit from such an approach. In those cases, however, I prefer this method to the alternative of burdening the developer with requirements of my library.
No comments :
Post a Comment