Follow-up Comment #1, bug #64295 (project make): This patch implements make abi versioning for loadable plugins.
The proposed patch is binary compatible with existing plugins. This patch allows make to detect if a plugin is binary compatible and exit with an error in the case of a binary incompatible plugin. The patch embeds the version of make abi to the plugin in the form of a strong symbol at build time. Then at load time make can know which version of abi each plugin was built with. This allows make to compare the needed abi version against its load-time version and exit with an error message, if the pluging was built with an incompatible version. The patch sets the initial version of make abi to 1.0. Suppose have mk_temp.so plugin built with make abi 1.0. $ ls makefile mk_temp.c $ cat mk_temp.c #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <gnumake.h> #include <gnumake_abi_version.h> int plugin_is_GPL_compatible; struct tmpfile { struct tmpfile *next; char *name; }; static struct tmpfile *files = NULL; static char * gen_tmpfile(const char *nm, unsigned int argc, char **argv) { int fd; /* Compute the size of the filename and allocate space for it. */ int len = strlen (argv[0]) + 6 + 1; char *buf = gmk_alloc (len); strcpy (buf, argv[0]); strcat (buf, "XXXXXX"); fd = mkstemp(buf); if (fd >= 0) { struct tmpfile *new = malloc (sizeof (struct tmpfile)); new->name = strdup (buf); new->next = files; files = new; /* Don't leak the file descriptor. */ close (fd); return buf; } /* Failure. */ fprintf (stderr, "mkstemp(%s) failed: %s\n", buf, strerror (errno)); gmk_free (buf); return NULL; } int mk_temp_gmk_setup (unsigned int abi, const gmk_floc *floc) { printf ("mk_temp plugin abi %u loaded from %s:%lu, needed abi %d.%d\n", abi, floc->filenm, floc->lineno, GMK_ABI_VERSION, GMK_ABI_AGE); /* Register the function with make name "mk-temp". */ gmk_add_function ("mk-temp", gen_tmpfile, 1, 1, 1); return 1; } void mk_temp_gmk_unload () { while (files) { struct tmpfile *f = files; files = f->next; printf ("mk_temp removing %s\n", f->name); remove (f->name); free (f->name); free (f); } printf ("mk_temp plugin closed\n"); } $ cat makefile all: @echo Temporary file: $(mk-temp tmpfile.) @echo Temporary file: $(mk-temp tmpfile.) -load mk_temp.so mk_temp.so: mk_temp.c; $(CC) -I ~/src/gmake/make/src -shared -fPIC -o $@ $^ $ make cc -I ~/src/gmake/make/src -shared -fPIC -o mk_temp.so mk_temp.c mk_temp plugin abi 1 loaded from makefile:5, needed abi 1.0 Temporary file: tmpfile.Uh53l3 Temporary file: tmpfile.7EQCH3 mk_temp removing tmpfile.7EQCH3 mk_temp removing tmpfile.Uh53l3 mk_temp plugin closed $ The plugin included gnumake_abi_version.h. mk_temp_gmk_setup uses macros GMK_VERSION, GMK_AGE. Then we keep mk_temp.so intact and introduce a compatible change to make abi and set the version to 2.1 and rebuild make. At load time make reads 1.0 from mk_temp.so and compares its current abi 2.1 against 1.0 and proceeds with loading the plugin. $ make --debug=v |tail -17 Loading symbol mk_temp_gmk_setup from mk_temp.so Loaded shared object mk_temp.so Make abi 2.1, mk_temp.so needed abi 1.0 Detected symbol mk_temp_gmk_unload in mk_temp.so mk_temp plugin abi 2 loaded from makefile:5, needed abi 1.0 Updating makefiles.... Updating goal targets.... Considering target file 'all'. File 'all' does not exist. Finished prerequisites of target file 'all'. Must remake target 'all'. Temporary file: tmpfile.mKD3cK Temporary file: tmpfile.0fr5VI Successfully remade target file 'all'. mk_temp removing tmpfile.0fr5VI mk_temp removing tmpfile.mKD3cK mk_temp plugin closed $ Now we introduce an incompatible change to make abi and set the version to 3.0 and rebuild make. At load time make reads 1.0 from mk_temp.so and compares 3.0 against 1.0 and exits with an error message. $ make --debug=v 2>&1 |tail -6 Reading makefiles... Reading makefile 'makefile'... Loading symbol mk_temp_gmk_setup from mk_temp.so Loaded shared object mk_temp.so Make abi 3.0, mk_temp.so needed abi 1.0 makefile:5: *** mk_temp.so needed abi 1.0 is incompatible with make abi 3.0. Stop. Tested on sunos (32 and 64 bit), linux (32 and 64 bit) and aix (64 bit). _______________________________________________________ Reply to this item at: <https://savannah.gnu.org/bugs/?64295> _______________________________________________ Message sent via Savannah https://savannah.gnu.org/